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