001/*
002 * Copyright 2009-2017 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2009-2017 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.IOException;
026import java.io.OutputStream;
027import java.io.Serializable;
028import java.nio.ByteBuffer;
029import java.util.concurrent.atomic.AtomicBoolean;
030
031import com.unboundid.util.ByteStringBuffer;
032import com.unboundid.util.DebugType;
033import com.unboundid.util.Mutable;
034import com.unboundid.util.ThreadSafety;
035import com.unboundid.util.ThreadSafetyLevel;
036
037import static com.unboundid.util.Debug.*;
038
039
040
041/**
042 * This class provides a mechanism for writing one or more ASN.1 elements into a
043 * byte string buffer.  It may be cleared and re-used any number of times, and
044 * the contents may be written to an {@code OutputStream} or {@code ByteBuffer},
045 * or copied to a byte array.  {@code ASN1Buffer} instances are not threadsafe
046 * and should not be accessed concurrently by multiple threads.
047 */
048@Mutable()
049@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
050public final class ASN1Buffer
051       implements Serializable
052{
053  /**
054   * The default maximum buffer size.
055   */
056  private static final int DEFAULT_MAX_BUFFER_SIZE = 1048576;
057
058
059
060  /**
061   * An array that will be inserted when completing a sequence whose
062   * multi-byte length should be encoded with one byte for the header and one
063   * byte for the number of value bytes.
064   */
065  private static final byte[] MULTIBYTE_LENGTH_HEADER_PLUS_ONE =
066       { (byte) 0x81, (byte) 0x00 };
067
068
069
070  /**
071   * An array that will be inserted when completing a sequence whose
072   * multi-byte length should be encoded with one byte for the header and two
073   * bytes for the number of value bytes.
074   */
075  private static final byte[] MULTIBYTE_LENGTH_HEADER_PLUS_TWO =
076       { (byte) 0x82, (byte) 0x00, (byte) 0x00 };
077
078
079
080  /**
081   * An array that will be inserted when completing a sequence whose
082   * multi-byte length should be encoded with one byte for the header and three
083   * bytes for the number of value bytes.
084   */
085  private static final byte[] MULTIBYTE_LENGTH_HEADER_PLUS_THREE =
086       { (byte) 0x83, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
087
088
089
090  /**
091   * An array that will be inserted when completing a sequence whose
092   * multi-byte length should be encoded with one byte for the header and four
093   * bytes for the number of value bytes.
094   */
095  private static final byte[] MULTIBYTE_LENGTH_HEADER_PLUS_FOUR =
096       { (byte) 0x84, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
097
098
099
100  /**
101   * The serial version UID for this serializable class.
102   */
103  private static final long serialVersionUID = -4898230771376551562L;
104
105
106
107  // Indicates whether to zero out the contents of the buffer the next time it
108  // is cleared in order to wipe out any sensitive data it may contain.
109  private final AtomicBoolean zeroBufferOnClear;
110
111  // The buffer to which all data will be written.
112  private final ByteStringBuffer buffer;
113
114  // The maximum buffer size that should be retained.
115  private final int maxBufferSize;
116
117
118
119  /**
120   * Creates a new instance of this ASN.1 buffer.
121   */
122  public ASN1Buffer()
123  {
124    this(DEFAULT_MAX_BUFFER_SIZE);
125  }
126
127
128
129  /**
130   * Creates a new instance of this ASN.1 buffer with an optional maximum
131   * retained size.  If a maximum size is defined, then this buffer may be used
132   * to hold elements larger than that, but when the buffer is cleared it will
133   * be shrunk to the maximum size.
134   *
135   * @param  maxBufferSize  The maximum buffer size that will be retained by
136   *                        this ASN.1 buffer.  A value less than or equal to
137   *                        zero indicates that no maximum size should be
138   *                        enforced.
139   */
140  public ASN1Buffer(final int maxBufferSize)
141  {
142    this.maxBufferSize = maxBufferSize;
143
144    buffer            = new ByteStringBuffer();
145    zeroBufferOnClear = new AtomicBoolean(false);
146  }
147
148
149
150  /**
151   * Indicates whether the content of the buffer should be zeroed out the next
152   * time it is cleared in order to wipe any sensitive information it may
153   * contain.
154   *
155   * @return  {@code true} if the content of the buffer should be zeroed out the
156   *          next time it is cleared, or {@code false} if not.
157   */
158  public boolean zeroBufferOnClear()
159  {
160    return zeroBufferOnClear.get();
161  }
162
163
164
165  /**
166   * Specifies that the content of the buffer should be zeroed out the next time
167   * it is cleared in order to wipe any sensitive information it may contain.
168   */
169  public void setZeroBufferOnClear()
170  {
171    zeroBufferOnClear.set(true);
172  }
173
174
175
176  /**
177   * Clears the contents of this buffer.  If there are any outstanding sequences
178   * or sets that have been created but not closed, then they must no longer be
179   * used and any attempt to do so may yield unpredictable results.
180   */
181  public void clear()
182  {
183    buffer.clear(zeroBufferOnClear.getAndSet(false));
184
185    if ((maxBufferSize > 0) && (buffer.capacity() > maxBufferSize))
186    {
187      buffer.setCapacity(maxBufferSize);
188    }
189  }
190
191
192
193  /**
194   * Retrieves the current length of this buffer in bytes.
195   *
196   * @return  The current length of this buffer in bytes.
197   */
198  public int length()
199  {
200    return buffer.length();
201  }
202
203
204
205  /**
206   * Adds the provided ASN.1 element to this ASN.1 buffer.
207   *
208   * @param  element  The element to be added.  It must not be {@code null}.
209   */
210  public void addElement(final ASN1Element element)
211  {
212    element.encodeTo(buffer);
213  }
214
215
216
217  /**
218   * Adds a Boolean element to this ASN.1 buffer using the default BER type.
219   *
220   * @param  booleanValue  The value to use for the Boolean element.
221   */
222  public void addBoolean(final boolean booleanValue)
223  {
224    addBoolean(ASN1Constants.UNIVERSAL_BOOLEAN_TYPE, booleanValue);
225  }
226
227
228
229  /**
230   * Adds a Boolean element to this ASN.1 buffer using the provided BER type.
231   *
232   * @param  type          The BER type to use for the Boolean element.
233   * @param  booleanValue  The value to use for the Boolean element.
234   */
235  public void addBoolean(final byte type, final boolean booleanValue)
236  {
237    buffer.append(type);
238    buffer.append((byte) 0x01);
239
240    if (booleanValue)
241    {
242      buffer.append((byte) 0xFF);
243    }
244    else
245    {
246      buffer.append((byte) 0x00);
247    }
248  }
249
250
251
252  /**
253   * Adds an enumerated element to this ASN.1 buffer using the default BER type.
254   *
255   * @param  intValue  The value to use for the enumerated element.
256   */
257  public void addEnumerated(final int intValue)
258  {
259    addInteger(ASN1Constants.UNIVERSAL_ENUMERATED_TYPE, intValue);
260  }
261
262
263
264  /**
265   * Adds an enumerated element to this ASN.1 buffer using the provided BER
266   * type.
267   *
268   * @param  type      The BER type to use for the enumerated element.
269   * @param  intValue  The value to use for the enumerated element.
270   */
271  public void addEnumerated(final byte type, final int intValue)
272  {
273    addInteger(type, intValue);
274  }
275
276
277
278  /**
279   * Adds an integer element to this ASN.1 buffer using the default BER type.
280   *
281   * @param  intValue  The value to use for the integer element.
282   */
283  public void addInteger(final int intValue)
284  {
285    addInteger(ASN1Constants.UNIVERSAL_INTEGER_TYPE, intValue);
286  }
287
288
289
290  /**
291   * Adds an integer element to this ASN.1 buffer using the provided BER type.
292   *
293   * @param  type      The BER type to use for the integer element.
294   * @param  intValue  The value to use for the integer element.
295   */
296  public void addInteger(final byte type, final int intValue)
297  {
298    buffer.append(type);
299
300    if (intValue < 0)
301    {
302      if ((intValue & 0xFFFFFF80) == 0xFFFFFF80)
303      {
304        buffer.append((byte) 0x01);
305        buffer.append((byte) (intValue & 0xFF));
306      }
307      else if ((intValue & 0xFFFF8000) == 0xFFFF8000)
308      {
309        buffer.append((byte) 0x02);
310        buffer.append((byte) ((intValue >> 8) & 0xFF));
311        buffer.append((byte) (intValue & 0xFF));
312      }
313      else if ((intValue & 0xFF800000) == 0xFF800000)
314      {
315        buffer.append((byte) 0x03);
316        buffer.append((byte) ((intValue >> 16) & 0xFF));
317        buffer.append((byte) ((intValue >> 8) & 0xFF));
318        buffer.append((byte) (intValue & 0xFF));
319      }
320      else
321      {
322        buffer.append((byte) 0x04);
323        buffer.append((byte) ((intValue >> 24) & 0xFF));
324        buffer.append((byte) ((intValue >> 16) & 0xFF));
325        buffer.append((byte) ((intValue >> 8) & 0xFF));
326        buffer.append((byte) (intValue & 0xFF));
327      }
328    }
329    else
330    {
331      if ((intValue & 0x0000007F) == intValue)
332      {
333        buffer.append((byte) 0x01);
334        buffer.append((byte) (intValue & 0x7F));
335      }
336      else if ((intValue & 0x00007FFF) == intValue)
337      {
338        buffer.append((byte) 0x02);
339        buffer.append((byte) ((intValue >> 8) & 0x7F));
340        buffer.append((byte) (intValue & 0xFF));
341      }
342      else if ((intValue & 0x007FFFFF) == intValue)
343      {
344        buffer.append((byte) 0x03);
345        buffer.append((byte) ((intValue >> 16) & 0x7F));
346        buffer.append((byte) ((intValue >> 8) & 0xFF));
347        buffer.append((byte) (intValue & 0xFF));
348      }
349      else
350      {
351        buffer.append((byte) 0x04);
352        buffer.append((byte) ((intValue >> 24) & 0x7F));
353        buffer.append((byte) ((intValue >> 16) & 0xFF));
354        buffer.append((byte) ((intValue >> 8) & 0xFF));
355        buffer.append((byte) (intValue & 0xFF));
356      }
357    }
358  }
359
360
361
362  /**
363   * Adds an integer element to this ASN.1 buffer using the default BER type.
364   *
365   * @param  longValue  The value to use for the integer element.
366   */
367  public void addInteger(final long longValue)
368  {
369    addInteger(ASN1Constants.UNIVERSAL_INTEGER_TYPE, longValue);
370  }
371
372
373
374  /**
375   * Adds an integer element to this ASN.1 buffer using the provided BER type.
376   *
377   * @param  type       The BER type to use for the integer element.
378   * @param  longValue  The value to use for the integer element.
379   */
380  public void addInteger(final byte type, final long longValue)
381  {
382    buffer.append(type);
383
384    if (longValue < 0)
385    {
386      if ((longValue & 0xFFFFFFFFFFFFFF80L) == 0xFFFFFFFFFFFFFF80L)
387      {
388        buffer.append((byte) 0x01);
389        buffer.append((byte) (longValue & 0xFFL));
390      }
391      else if ((longValue & 0xFFFFFFFFFFFF8000L) == 0xFFFFFFFFFFFF8000L)
392      {
393        buffer.append((byte) 0x02);
394        buffer.append((byte) ((longValue >> 8) & 0xFFL));
395        buffer.append((byte) (longValue & 0xFFL));
396      }
397      else if ((longValue & 0xFFFFFFFFFF800000L) == 0xFFFFFFFFFF800000L)
398      {
399        buffer.append((byte) 0x03);
400        buffer.append((byte) ((longValue >> 16) & 0xFFL));
401        buffer.append((byte) ((longValue >> 8) & 0xFFL));
402        buffer.append((byte) (longValue & 0xFFL));
403      }
404      else if ((longValue & 0xFFFFFFFF80000000L) == 0xFFFFFFFF80000000L)
405      {
406        buffer.append((byte) 0x04);
407        buffer.append((byte) ((longValue >> 24) & 0xFFL));
408        buffer.append((byte) ((longValue >> 16) & 0xFFL));
409        buffer.append((byte) ((longValue >> 8) & 0xFFL));
410        buffer.append((byte) (longValue & 0xFFL));
411      }
412      else if ((longValue & 0xFFFFFF8000000000L) == 0xFFFFFF8000000000L)
413      {
414        buffer.append((byte) 0x05);
415        buffer.append((byte) ((longValue >> 32) & 0xFFL));
416        buffer.append((byte) ((longValue >> 24) & 0xFFL));
417        buffer.append((byte) ((longValue >> 16) & 0xFFL));
418        buffer.append((byte) ((longValue >> 8) & 0xFFL));
419        buffer.append((byte) (longValue & 0xFFL));
420      }
421      else if ((longValue & 0xFFFF800000000000L) == 0xFFFF800000000000L)
422      {
423        buffer.append((byte) 0x06);
424        buffer.append((byte) ((longValue >> 40) & 0xFFL));
425        buffer.append((byte) ((longValue >> 32) & 0xFFL));
426        buffer.append((byte) ((longValue >> 24) & 0xFFL));
427        buffer.append((byte) ((longValue >> 16) & 0xFFL));
428        buffer.append((byte) ((longValue >> 8) & 0xFFL));
429        buffer.append((byte) (longValue & 0xFFL));
430      }
431      else if ((longValue & 0xFF80000000000000L) == 0xFF80000000000000L)
432      {
433        buffer.append((byte) 0x07);
434        buffer.append((byte) ((longValue >> 48) & 0xFFL));
435        buffer.append((byte) ((longValue >> 40) & 0xFFL));
436        buffer.append((byte) ((longValue >> 32) & 0xFFL));
437        buffer.append((byte) ((longValue >> 24) & 0xFFL));
438        buffer.append((byte) ((longValue >> 16) & 0xFFL));
439        buffer.append((byte) ((longValue >> 8) & 0xFFL));
440        buffer.append((byte) (longValue & 0xFFL));
441      }
442      else
443      {
444        buffer.append((byte) 0x08);
445        buffer.append((byte) ((longValue >> 56) & 0xFFL));
446        buffer.append((byte) ((longValue >> 48) & 0xFFL));
447        buffer.append((byte) ((longValue >> 40) & 0xFFL));
448        buffer.append((byte) ((longValue >> 32) & 0xFFL));
449        buffer.append((byte) ((longValue >> 24) & 0xFFL));
450        buffer.append((byte) ((longValue >> 16) & 0xFFL));
451        buffer.append((byte) ((longValue >> 8) & 0xFFL));
452        buffer.append((byte) (longValue & 0xFFL));
453      }
454    }
455    else
456    {
457      if ((longValue & 0x000000000000007FL) == longValue)
458      {
459        buffer.append((byte) 0x01);
460        buffer.append((byte) (longValue & 0x7FL));
461      }
462      else if ((longValue & 0x0000000000007FFFL) == longValue)
463      {
464        buffer.append((byte) 0x02);
465        buffer.append((byte) ((longValue >> 8) & 0x7FL));
466        buffer.append((byte) (longValue & 0xFFL));
467      }
468      else if ((longValue & 0x00000000007FFFFFL) == longValue)
469      {
470        buffer.append((byte) 0x03);
471        buffer.append((byte) ((longValue >> 16) & 0x7FL));
472        buffer.append((byte) ((longValue >> 8) & 0xFFL));
473        buffer.append((byte) (longValue & 0xFFL));
474      }
475      else if ((longValue & 0x000000007FFFFFFFL) == longValue)
476      {
477        buffer.append((byte) 0x04);
478        buffer.append((byte) ((longValue >> 24) & 0x7FL));
479        buffer.append((byte) ((longValue >> 16) & 0xFFL));
480        buffer.append((byte) ((longValue >> 8) & 0xFFL));
481        buffer.append((byte) (longValue & 0xFFL));
482      }
483      else if ((longValue & 0x0000007FFFFFFFFFL) == longValue)
484      {
485        buffer.append((byte) 0x05);
486        buffer.append((byte) ((longValue >> 32) & 0x7FL));
487        buffer.append((byte) ((longValue >> 24) & 0xFFL));
488        buffer.append((byte) ((longValue >> 16) & 0xFFL));
489        buffer.append((byte) ((longValue >> 8) & 0xFFL));
490        buffer.append((byte) (longValue & 0xFFL));
491      }
492      else if ((longValue & 0x00007FFFFFFFFFFFL) == longValue)
493      {
494        buffer.append((byte) 0x06);
495        buffer.append((byte) ((longValue >> 40) & 0x7FL));
496        buffer.append((byte) ((longValue >> 32) & 0xFFL));
497        buffer.append((byte) ((longValue >> 24) & 0xFFL));
498        buffer.append((byte) ((longValue >> 16) & 0xFFL));
499        buffer.append((byte) ((longValue >> 8) & 0xFFL));
500        buffer.append((byte) (longValue & 0xFFL));
501      }
502      else if ((longValue & 0x007FFFFFFFFFFFFFL) == longValue)
503      {
504        buffer.append((byte) 0x07);
505        buffer.append((byte) ((longValue >> 48) & 0x7FL));
506        buffer.append((byte) ((longValue >> 40) & 0xFFL));
507        buffer.append((byte) ((longValue >> 32) & 0xFFL));
508        buffer.append((byte) ((longValue >> 24) & 0xFFL));
509        buffer.append((byte) ((longValue >> 16) & 0xFFL));
510        buffer.append((byte) ((longValue >> 8) & 0xFFL));
511        buffer.append((byte) (longValue & 0xFFL));
512      }
513      else
514      {
515        buffer.append((byte) 0x08);
516        buffer.append((byte) ((longValue >> 56) & 0x7FL));
517        buffer.append((byte) ((longValue >> 48) & 0xFFL));
518        buffer.append((byte) ((longValue >> 40) & 0xFFL));
519        buffer.append((byte) ((longValue >> 32) & 0xFFL));
520        buffer.append((byte) ((longValue >> 24) & 0xFFL));
521        buffer.append((byte) ((longValue >> 16) & 0xFFL));
522        buffer.append((byte) ((longValue >> 8) & 0xFFL));
523        buffer.append((byte) (longValue & 0xFFL));
524      }
525    }
526  }
527
528
529
530  /**
531   * Adds a null element to this ASN.1 buffer using the default BER type.
532   */
533  public void addNull()
534  {
535    addNull(ASN1Constants.UNIVERSAL_NULL_TYPE);
536  }
537
538
539
540  /**
541   * Adds a null element to this ASN.1 buffer using the provided BER type.
542   *
543   * @param  type  The BER type to use for the null element.
544   */
545  public void addNull(final byte type)
546  {
547    buffer.append(type);
548    buffer.append((byte) 0x00);
549  }
550
551
552
553  /**
554   * Adds an octet string element to this ASN.1 buffer using the default BER
555   * type and no value.
556   */
557  public void addOctetString()
558  {
559    addOctetString(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE);
560  }
561
562
563
564  /**
565   * Adds an octet string element to this ASN.1 buffer using the provided BER
566   * type and no value.
567   *
568   * @param  type  The BER type to use for the octet string element.
569   */
570  public void addOctetString(final byte type)
571  {
572    buffer.append(type);
573    buffer.append((byte) 0x00);
574  }
575
576
577
578  /**
579   * Adds an octet string element to this ASN.1 buffer using the default BER
580   * type.
581   *
582   * @param  value  The value to use for the octet string element.
583   */
584  public void addOctetString(final byte[] value)
585  {
586    addOctetString(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE, value);
587  }
588
589
590
591  /**
592   * Adds an octet string element to this ASN.1 buffer using the default BER
593   * type.
594   *
595   * @param  value  The value to use for the octet string element.
596   */
597  public void addOctetString(final CharSequence value)
598  {
599    if (value == null)
600    {
601      addOctetString(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE);
602    }
603    else
604    {
605      addOctetString(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE,
606                     value.toString());
607    }
608  }
609
610
611
612  /**
613   * Adds an octet string element to this ASN.1 buffer using the default BER
614   * type.
615   *
616   * @param  value  The value to use for the octet string element.
617   */
618  public void addOctetString(final String value)
619  {
620    addOctetString(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE, value);
621  }
622
623
624
625  /**
626   * Adds an octet string element to this ASN.1 buffer using the provided BER
627   * type.
628   *
629   * @param  type   The BER type to use for the octet string element.
630   * @param  value  The value to use for the octet string element.
631   */
632  public void addOctetString(final byte type, final byte[] value)
633  {
634    buffer.append(type);
635
636    if (value == null)
637    {
638      buffer.append((byte) 0x00);
639    }
640    else
641    {
642      ASN1Element.encodeLengthTo(value.length, buffer);
643      buffer.append(value);
644    }
645  }
646
647
648
649  /**
650   * Adds an octet string element to this ASN.1 buffer using the provided BER
651   * type.
652   *
653   * @param  type   The BER type to use for the octet string element.
654   * @param  value  The value to use for the octet string element.
655   */
656  public void addOctetString(final byte type, final CharSequence value)
657  {
658    if (value == null)
659    {
660      addOctetString(type);
661    }
662    else
663    {
664      addOctetString(type, value.toString());
665    }
666  }
667
668
669
670  /**
671   * Adds an octet string element to this ASN.1 buffer using the provided BER
672   * type.
673   *
674   * @param  type   The BER type to use for the octet string element.
675   * @param  value  The value to use for the octet string element.
676   */
677  public void addOctetString(final byte type, final String value)
678  {
679    buffer.append(type);
680
681    if (value == null)
682    {
683      buffer.append((byte) 0x00);
684    }
685    else
686    {
687      // We'll assume that the string contains only ASCII characters and
688      // therefore the number of bytes will equal the number of characters.
689      // However, save the position in case we're wrong and need to re-encode.
690      final int lengthStartPos = buffer.length();
691      ASN1Element.encodeLengthTo(value.length(), buffer);
692
693      final int valueStartPos = buffer.length();
694      buffer.append(value);
695
696      if (buffer.length() != (valueStartPos + value.length()))
697      {
698        final byte[] valueBytes = new byte[buffer.length() - valueStartPos];
699        System.arraycopy(buffer.getBackingArray(), valueStartPos, valueBytes, 0,
700                         valueBytes.length);
701
702        buffer.setLength(lengthStartPos);
703        ASN1Element.encodeLengthTo(valueBytes.length, buffer);
704        buffer.append(valueBytes);
705      }
706    }
707  }
708
709
710
711  /**
712   * Begins adding elements to an ASN.1 sequence using the default BER type.
713   *
714   * @return  An object that may be used to indicate when the end of the
715   *          sequence has been reached.  Once all embedded sequence elements
716   *          have been added, then the {@link ASN1BufferSequence#end} method
717   *          MUST be called to ensure that the sequence is properly encoded.
718   */
719  public ASN1BufferSequence beginSequence()
720  {
721    return beginSequence(ASN1Constants.UNIVERSAL_SEQUENCE_TYPE);
722  }
723
724
725
726  /**
727   * Begins adding elements to an ASN.1 sequence using the provided BER type.
728   *
729   * @param  type  The BER type to use for the sequence.
730   *
731   * @return  An object that may be used to indicate when the end of the
732   *          sequence has been reached.  Once all embedded sequence elements
733   *          have been added, then the {@link ASN1BufferSequence#end} method
734   *          MUST be called to ensure that the sequence is properly encoded.
735   */
736  public ASN1BufferSequence beginSequence(final byte type)
737  {
738    buffer.append(type);
739    return new ASN1BufferSequence(this);
740  }
741
742
743
744  /**
745   * Begins adding elements to an ASN.1 set using the default BER type.
746   *
747   * @return  An object that may be used to indicate when the end of the set has
748   *          been reached.  Once all embedded set elements have been added,
749   *          then the {@link ASN1BufferSet#end} method MUST be called to ensure
750   *          that the set is properly encoded.
751   */
752  public ASN1BufferSet beginSet()
753  {
754    return beginSet(ASN1Constants.UNIVERSAL_SET_TYPE);
755  }
756
757
758
759  /**
760   * Begins adding elements to an ASN.1 set using the provided BER type.
761   *
762   * @param  type  The BER type to use for the set.
763   *
764   * @return  An object that may be used to indicate when the end of the set has
765   *          been reached.  Once all embedded set elements have been added,
766   *          then the {@link ASN1BufferSet#end} method MUST be called to ensure
767   *          that the set is properly encoded.
768   */
769  public ASN1BufferSet beginSet(final byte type)
770  {
771    buffer.append(type);
772    return new ASN1BufferSet(this);
773  }
774
775
776
777  /**
778   * Ensures that the appropriate length is inserted into the internal buffer
779   * after all elements in a sequence or set have been added.
780   *
781   * @param  valueStartPos  The position in which the first value was added.
782   */
783  void endSequenceOrSet(final int valueStartPos)
784  {
785    final int length = buffer.length() - valueStartPos;
786    if (length == 0)
787    {
788      buffer.append((byte) 0x00);
789      return;
790    }
791
792    if ((length & 0x7F) == length)
793    {
794      buffer.insert(valueStartPos, (byte) length);
795    }
796    else if ((length & 0xFF) == length)
797    {
798      buffer.insert(valueStartPos, MULTIBYTE_LENGTH_HEADER_PLUS_ONE);
799
800      final byte[] backingArray = buffer.getBackingArray();
801      backingArray[valueStartPos+1] = (byte) (length & 0xFF);
802    }
803    else if ((length & 0xFFFF) == length)
804    {
805      buffer.insert(valueStartPos, MULTIBYTE_LENGTH_HEADER_PLUS_TWO);
806
807      final byte[] backingArray = buffer.getBackingArray();
808      backingArray[valueStartPos+1] = (byte) ((length >> 8) & 0xFF);
809      backingArray[valueStartPos+2] = (byte) (length & 0xFF);
810    }
811    else if ((length & 0xFFFFFF) == length)
812    {
813      buffer.insert(valueStartPos, MULTIBYTE_LENGTH_HEADER_PLUS_THREE);
814
815      final byte[] backingArray = buffer.getBackingArray();
816      backingArray[valueStartPos+1] = (byte) ((length >> 16) & 0xFF);
817      backingArray[valueStartPos+2] = (byte) ((length >> 8) & 0xFF);
818      backingArray[valueStartPos+3] = (byte) (length & 0xFF);
819    }
820    else
821    {
822      buffer.insert(valueStartPos, MULTIBYTE_LENGTH_HEADER_PLUS_FOUR);
823
824      final byte[] backingArray = buffer.getBackingArray();
825      backingArray[valueStartPos+1] = (byte) ((length >> 24) & 0xFF);
826      backingArray[valueStartPos+2] = (byte) ((length >> 16) & 0xFF);
827      backingArray[valueStartPos+3] = (byte) ((length >> 8) & 0xFF);
828      backingArray[valueStartPos+4] = (byte) (length & 0xFF);
829    }
830  }
831
832
833
834  /**
835   * Writes the contents of this buffer to the provided output stream.
836   *
837   * @param  outputStream  The output stream to which the data should be
838   *                       written.
839   *
840   * @throws  IOException  If a problem occurs while writing to the provided
841   *                       output stream.
842   */
843  public void writeTo(final OutputStream outputStream)
844         throws IOException
845  {
846    if (debugEnabled(DebugType.ASN1))
847    {
848      debugASN1Write(this);
849    }
850
851    buffer.write(outputStream);
852  }
853
854
855
856  /**
857   * Retrieves a byte array containing the contents of this ASN.1 buffer.
858   *
859   * @return  A byte array containing the contents of this ASN.1 buffer.
860   */
861  public byte[] toByteArray()
862  {
863    return buffer.toByteArray();
864  }
865
866
867
868  /**
869   * Retrieves a byte buffer that wraps the data associated with this ASN.1
870   * buffer.  The position will be set to the beginning of the data, and the
871   * limit will be set to one byte after the end of the data.  The contents
872   * of the returned byte buffer must not be altered in any way, and the
873   * contents of this ASN.1 buffer must not be altered until the
874   * {@code ByteBuffer} is no longer needed.
875   *
876   * @return  A byte buffer that wraps the data associated with this ASN.1
877   *          buffer.
878   */
879  public ByteBuffer asByteBuffer()
880  {
881    return ByteBuffer.wrap(buffer.getBackingArray(), 0, buffer.length());
882  }
883}