001    /*
002     * Copyright 2009-2016 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2009-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.IOException;
026    import java.io.OutputStream;
027    import java.io.Serializable;
028    import java.nio.ByteBuffer;
029    import java.util.concurrent.atomic.AtomicBoolean;
030    
031    import com.unboundid.util.ByteStringBuffer;
032    import com.unboundid.util.DebugType;
033    import com.unboundid.util.Mutable;
034    import com.unboundid.util.ThreadSafety;
035    import com.unboundid.util.ThreadSafetyLevel;
036    
037    import 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)
050    public 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    }