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 }