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 }