001 /*
002 * Copyright 2009-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2009-2014 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
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 }