001/* 002 * Copyright 2008-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2018 Ping Identity Corporation 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 */ 021package com.unboundid.util; 022 023 024 025import java.io.ByteArrayInputStream; 026import java.io.InputStream; 027import java.io.IOException; 028import java.io.OutputStream; 029import java.io.Serializable; 030import java.util.Arrays; 031 032import com.unboundid.asn1.ASN1OctetString; 033 034import static com.unboundid.util.UtilityMessages.*; 035 036 037 038/** 039 * This class provides a growable byte array to which data can be appended. 040 * Methods in this class are not synchronized. 041 */ 042@Mutable() 043@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 044public final class ByteStringBuffer 045 implements Serializable, Appendable 046{ 047 /** 048 * The default initial capacity for this buffer. 049 */ 050 private static final int DEFAULT_INITIAL_CAPACITY = 20; 051 052 053 054 /** 055 * The pre-allocated array that will be used for a boolean value of "false". 056 */ 057 private static final byte[] FALSE_VALUE_BYTES = StaticUtils.getBytes("false"); 058 059 060 061 /** 062 * The pre-allocated array that will be used for a boolean value of "true". 063 */ 064 private static final byte[] TRUE_VALUE_BYTES = StaticUtils.getBytes("true"); 065 066 067 068 /** 069 * A thread-local byte array that will be used for holding numeric values 070 * to append to the buffer. 071 */ 072 private static final ThreadLocal<byte[]> TEMP_NUMBER_BUFFER = 073 new ThreadLocal<>(); 074 075 076 077 /** 078 * The serial version UID for this serializable class. 079 */ 080 private static final long serialVersionUID = 2899392249591230998L; 081 082 083 084 // The backing array for this buffer. 085 private byte[] array; 086 087 // The length of the backing array. 088 private int capacity; 089 090 // The position at which to append the next data. 091 private int endPos; 092 093 094 095 /** 096 * Creates a new empty byte string buffer with a default initial capacity. 097 */ 098 public ByteStringBuffer() 099 { 100 this(DEFAULT_INITIAL_CAPACITY); 101 } 102 103 104 105 /** 106 * Creates a new byte string buffer with the specified capacity. 107 * 108 * @param initialCapacity The initial capacity to use for the buffer. It 109 * must be greater than or equal to zero. 110 */ 111 public ByteStringBuffer(final int initialCapacity) 112 { 113 array = new byte[initialCapacity]; 114 capacity = initialCapacity; 115 endPos = 0; 116 } 117 118 119 120 /** 121 * Appends the provided boolean value to this buffer. 122 * 123 * @param b The boolean value to be appended to this buffer. 124 * 125 * @return A reference to this buffer. 126 */ 127 public ByteStringBuffer append(final boolean b) 128 { 129 if (b) 130 { 131 return append(TRUE_VALUE_BYTES, 0, 4); 132 } 133 else 134 { 135 return append(FALSE_VALUE_BYTES, 0, 5); 136 } 137 } 138 139 140 141 /** 142 * Appends the provided byte to this buffer. 143 * 144 * @param b The byte to be appended to this buffer. 145 * 146 * @return A reference to this buffer. 147 */ 148 public ByteStringBuffer append(final byte b) 149 { 150 ensureCapacity(endPos + 1); 151 array[endPos++] = b; 152 return this; 153 } 154 155 156 157 /** 158 * Appends the contents of the provided byte array to this buffer. 159 * 160 * @param b The array whose contents should be appended to this buffer. It 161 * must not be {@code null}. 162 * 163 * @return A reference to this buffer. 164 * 165 * @throws NullPointerException If the provided array is {@code null}. 166 */ 167 public ByteStringBuffer append(final byte[] b) 168 throws NullPointerException 169 { 170 if (b == null) 171 { 172 final NullPointerException e = 173 new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get()); 174 Debug.debugCodingError(e); 175 throw e; 176 } 177 178 return append(b, 0, b.length); 179 } 180 181 182 183 /** 184 * Appends the specified portion of the provided byte array to this buffer. 185 * 186 * @param b The array whose contents should be appended to this buffer. 187 * @param off The offset within the array at which to begin copying data. 188 * @param len The number of bytes to copy. 189 * 190 * @return A reference to this buffer. 191 * 192 * @throws NullPointerException If the provided array is {@code null}. 193 * 194 * @throws IndexOutOfBoundsException If the offset or length are negative, 195 * if the offset plus the length is beyond 196 * the end of the provided array. 197 */ 198 public ByteStringBuffer append(final byte[] b, final int off, final int len) 199 throws NullPointerException, IndexOutOfBoundsException 200 { 201 if (b == null) 202 { 203 final NullPointerException e = 204 new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get()); 205 Debug.debugCodingError(e); 206 throw e; 207 } 208 209 if ((off < 0) || (len < 0) || (off+len > b.length)) 210 { 211 final String message; 212 if (off < 0) 213 { 214 message = ERR_BS_BUFFER_OFFSET_NEGATIVE.get(off); 215 } 216 else if (len < 0) 217 { 218 message = ERR_BS_BUFFER_LENGTH_NEGATIVE.get(len); 219 } 220 else 221 { 222 message = ERR_BS_BUFFER_OFFSET_PLUS_LENGTH_TOO_LARGE.get(off, len, 223 b.length); 224 } 225 226 final IndexOutOfBoundsException e = 227 new IndexOutOfBoundsException(message); 228 Debug.debugCodingError(e); 229 throw e; 230 } 231 232 if (len > 0) 233 { 234 ensureCapacity(endPos + len); 235 System.arraycopy(b, off, array, endPos, len); 236 endPos += len; 237 } 238 239 return this; 240 } 241 242 243 244 /** 245 * Appends the provided byte string to this buffer. 246 * 247 * @param b The byte string to be appended to this buffer. 248 * 249 * @return A reference to this buffer. 250 * 251 * @throws NullPointerException If the provided byte string is {@code null}. 252 */ 253 public ByteStringBuffer append(final ByteString b) 254 throws NullPointerException 255 { 256 if (b == null) 257 { 258 final NullPointerException e = 259 new NullPointerException(ERR_BS_BUFFER_BYTE_STRING_NULL.get()); 260 Debug.debugCodingError(e); 261 throw e; 262 } 263 264 b.appendValueTo(this); 265 return this; 266 } 267 268 269 270 /** 271 * Appends the provided byte string buffer to this buffer. 272 * 273 * @param buffer The buffer whose contents should be appended to this 274 * buffer. 275 * 276 * @return A reference to this buffer. 277 * 278 * @throws NullPointerException If the provided buffer is {@code null}. 279 */ 280 public ByteStringBuffer append(final ByteStringBuffer buffer) 281 throws NullPointerException 282 { 283 if (buffer == null) 284 { 285 final NullPointerException e = 286 new NullPointerException(ERR_BS_BUFFER_BUFFER_NULL.get()); 287 Debug.debugCodingError(e); 288 throw e; 289 } 290 291 return append(buffer.array, 0, buffer.endPos); 292 } 293 294 295 296 /** 297 * Appends the provided character to this buffer. 298 * 299 * @param c The character to be appended to this buffer. 300 * 301 * @return A reference to this buffer. 302 */ 303 @Override() 304 public ByteStringBuffer append(final char c) 305 { 306 final byte b = (byte) (c & 0x7F); 307 if (b == c) 308 { 309 ensureCapacity(endPos + 1); 310 array[endPos++] = b; 311 } 312 else 313 { 314 append(String.valueOf(c)); 315 } 316 317 return this; 318 } 319 320 321 322 /** 323 * Appends the contents of the provided character array to this buffer. 324 * 325 * @param c The array whose contents should be appended to this buffer. 326 * 327 * @return A reference to this buffer. 328 * 329 * @throws NullPointerException If the provided array is {@code null}. 330 */ 331 public ByteStringBuffer append(final char[] c) 332 throws NullPointerException 333 { 334 if (c == null) 335 { 336 final NullPointerException e = 337 new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get()); 338 Debug.debugCodingError(e); 339 throw e; 340 } 341 342 return append(c, 0, c.length); 343 } 344 345 346 347 /** 348 * Appends the specified portion of the provided character array to this 349 * buffer. 350 * 351 * @param c The array whose contents should be appended to this buffer. 352 * @param off The offset within the array at which to begin copying data. 353 * @param len The number of characters to copy. 354 * 355 * @return A reference to this buffer. 356 * 357 * @throws NullPointerException If the provided array is {@code null}. 358 * 359 * @throws IndexOutOfBoundsException If the offset or length are negative, 360 * if the offset plus the length is beyond 361 * the end of the provided array. 362 */ 363 public ByteStringBuffer append(final char[] c, final int off, final int len) 364 throws NullPointerException, IndexOutOfBoundsException 365 { 366 if (c == null) 367 { 368 final NullPointerException e = 369 new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get()); 370 Debug.debugCodingError(e); 371 throw e; 372 } 373 374 if ((off < 0) || (len < 0) || (off+len > c.length)) 375 { 376 final String message; 377 if (off < 0) 378 { 379 message = ERR_BS_BUFFER_OFFSET_NEGATIVE.get(off); 380 } 381 else if (len < 0) 382 { 383 message = ERR_BS_BUFFER_LENGTH_NEGATIVE.get(len); 384 } 385 else 386 { 387 message = ERR_BS_BUFFER_OFFSET_PLUS_LENGTH_TOO_LARGE.get(off, len, 388 c.length); 389 } 390 391 final IndexOutOfBoundsException e = 392 new IndexOutOfBoundsException(message); 393 Debug.debugCodingError(e); 394 throw e; 395 } 396 397 if (len > 0) 398 { 399 ensureCapacity(endPos + len); 400 401 int pos = off; 402 for (int i=0; i < len; i++, pos++) 403 { 404 final byte b = (byte) (c[pos] & 0x7F); 405 if (b == c[pos]) 406 { 407 array[endPos++] = b; 408 } 409 else 410 { 411 final String remainingString = 412 String.valueOf(c, pos, (off + len - pos)); 413 final byte[] remainingBytes = StaticUtils.getBytes(remainingString); 414 return append(remainingBytes); 415 } 416 } 417 } 418 419 return this; 420 } 421 422 423 424 /** 425 * Appends the provided character sequence to this buffer. 426 * 427 * @param s The character sequence to append to this buffer. 428 * 429 * @return A reference to this buffer. 430 * 431 * @throws NullPointerException If the provided character sequence is 432 * {@code null}. 433 */ 434 @Override() 435 public ByteStringBuffer append(final CharSequence s) 436 throws NullPointerException 437 { 438 return append(s, 0, s.length()); 439 } 440 441 442 443 /** 444 * Appends the provided character sequence to this buffer. 445 * 446 * @param s The character sequence to append to this buffer. 447 * @param start The position in the sequence of the first character in the 448 * sequence to be appended to this buffer. 449 * @param end The position in the sequence immediately after the position 450 * of the last character to be appended. 451 * 452 * @return A reference to this buffer. 453 * 454 * @throws NullPointerException If the provided character sequence is 455 * {@code null}. 456 * 457 * @throws IndexOutOfBoundsException If the provided start or end positions 458 * are outside the bounds of the given 459 * character sequence. 460 */ 461 @Override() 462 public ByteStringBuffer append(final CharSequence s, final int start, 463 final int end) 464 throws NullPointerException, IndexOutOfBoundsException 465 { 466 if (s == null) 467 { 468 final NullPointerException e = 469 new NullPointerException(ERR_BS_BUFFER_CHAR_SEQUENCE_NULL.get()); 470 Debug.debugCodingError(e); 471 throw e; 472 } 473 474 final char[] chars; 475 if (s instanceof String) 476 { 477 chars = ((String) s).toCharArray(); 478 } 479 else 480 { 481 chars = s.toString().toCharArray(); 482 } 483 484 return append(chars, start, end); 485 } 486 487 488 489 /** 490 * Appends the provided integer value to this buffer. 491 * 492 * @param i The integer value to be appended to this buffer. 493 * 494 * @return A reference to this buffer. 495 */ 496 public ByteStringBuffer append(final int i) 497 { 498 final int length = getBytes(i); 499 return append(TEMP_NUMBER_BUFFER.get(), 0, length); 500 } 501 502 503 504 /** 505 * Appends the provided long value to this buffer. 506 * 507 * @param l The long value to be appended to this buffer. 508 * 509 * @return A reference to this buffer. 510 */ 511 public ByteStringBuffer append(final long l) 512 { 513 final int length = getBytes(l); 514 return append(TEMP_NUMBER_BUFFER.get(), 0, length); 515 } 516 517 518 519 /** 520 * Inserts the provided boolean value to this buffer. 521 * 522 * @param pos The position at which the value is to be inserted. 523 * @param b The boolean value to be inserted into this buffer. 524 * 525 * @return A reference to this buffer. 526 * 527 * @throws IndexOutOfBoundsException If the specified position is negative 528 * or greater than the current length. 529 */ 530 public ByteStringBuffer insert(final int pos, final boolean b) 531 throws IndexOutOfBoundsException 532 { 533 if (b) 534 { 535 return insert(pos, TRUE_VALUE_BYTES, 0, 4); 536 } 537 else 538 { 539 return insert(pos, FALSE_VALUE_BYTES, 0, 5); 540 } 541 } 542 543 544 545 /** 546 * Inserts the provided byte at the specified position in this buffer. 547 * 548 * @param pos The position at which the byte is to be inserted. 549 * @param b The byte to be inserted into this buffer. 550 * 551 * @return A reference to this buffer. 552 * 553 * @throws IndexOutOfBoundsException If the specified position is negative 554 * or greater than the current length. 555 */ 556 public ByteStringBuffer insert(final int pos, final byte b) 557 throws IndexOutOfBoundsException 558 { 559 if ((pos < 0) || (pos > endPos)) 560 { 561 final String message; 562 if (pos < 0) 563 { 564 message = ERR_BS_BUFFER_POS_NEGATIVE.get(pos); 565 } 566 else 567 { 568 message = ERR_BS_BUFFER_POS_TOO_LARGE.get(pos, endPos); 569 } 570 571 final IndexOutOfBoundsException e = 572 new IndexOutOfBoundsException(message); 573 Debug.debugCodingError(e); 574 throw e; 575 } 576 else if (pos == endPos) 577 { 578 return append(b); 579 } 580 581 ensureCapacity(endPos + 1); 582 System.arraycopy(array, pos, array, pos+1, (endPos-pos)); 583 array[pos] = b; 584 endPos++; 585 return this; 586 } 587 588 589 590 /** 591 * Inserts the contents of the provided byte array at the specified position 592 * in this buffer. 593 * 594 * @param pos The position at which the data is to be inserted. 595 * @param b The array whose contents should be inserted into this buffer. 596 * 597 * @return A reference to this buffer. 598 * 599 * @throws NullPointerException If the provided array is {@code null}. 600 * 601 * @throws IndexOutOfBoundsException If the specified position is negative 602 * or greater than the current length. 603 */ 604 public ByteStringBuffer insert(final int pos, final byte[] b) 605 throws NullPointerException, IndexOutOfBoundsException 606 { 607 if (b == null) 608 { 609 final NullPointerException e = 610 new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get()); 611 Debug.debugCodingError(e); 612 throw e; 613 } 614 615 return insert(pos, b, 0, b.length); 616 } 617 618 619 620 /** 621 * Inserts a portion of the data in the provided array at the specified 622 * position in this buffer. 623 * 624 * Appends the specified portion of the provided byte array to this buffer. 625 * 626 * @param pos The position at which the data is to be inserted. 627 * @param b The array whose contents should be inserted into this buffer. 628 * @param off The offset within the array at which to begin copying data. 629 * @param len The number of bytes to copy. 630 * 631 * @return A reference to this buffer. 632 * 633 * @throws NullPointerException If the provided array is {@code null}. 634 * 635 * @throws IndexOutOfBoundsException If the specified position is negative 636 * or greater than the current length, if 637 * the offset or length are negative, if 638 * the offset plus the length is beyond 639 * the end of the provided array. 640 */ 641 public ByteStringBuffer insert(final int pos, final byte[] b, final int off, 642 final int len) 643 throws NullPointerException, IndexOutOfBoundsException 644 { 645 if (b == null) 646 { 647 final NullPointerException e = 648 new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get()); 649 Debug.debugCodingError(e); 650 throw e; 651 } 652 653 if ((pos < 0) || (pos > endPos) || (off < 0) || (len < 0) || 654 (off+len > b.length)) 655 { 656 final String message; 657 if (pos < 0) 658 { 659 message = ERR_BS_BUFFER_POS_NEGATIVE.get(pos); 660 } 661 else if (pos > endPos) 662 { 663 message = ERR_BS_BUFFER_POS_TOO_LARGE.get(pos, endPos); 664 } 665 else if (off < 0) 666 { 667 message = ERR_BS_BUFFER_OFFSET_NEGATIVE.get(off); 668 } 669 else if (len < 0) 670 { 671 message = ERR_BS_BUFFER_LENGTH_NEGATIVE.get(len); 672 } 673 else 674 { 675 message = ERR_BS_BUFFER_OFFSET_PLUS_LENGTH_TOO_LARGE.get(off, len, 676 b.length); 677 } 678 679 final IndexOutOfBoundsException e = 680 new IndexOutOfBoundsException(message); 681 Debug.debugCodingError(e); 682 throw e; 683 } 684 else if (len == 0) 685 { 686 return this; 687 } 688 else if (pos == endPos) 689 { 690 return append(b, off, len); 691 } 692 693 ensureCapacity(endPos + len); 694 System.arraycopy(array, pos, array, pos+len, (endPos-pos)); 695 System.arraycopy(b, off, array, pos, len); 696 endPos += len; 697 return this; 698 } 699 700 701 702 /** 703 * Inserts the provided byte string into this buffer at the specified 704 * position. 705 * 706 * @param pos The position at which the data is to be inserted. 707 * @param b The byte string to insert into this buffer. 708 * 709 * @return A reference to this buffer. 710 * 711 * @throws NullPointerException If the provided buffer is {@code null}. 712 * 713 * @throws IndexOutOfBoundsException If the specified position is negative 714 * or greater than the current length. 715 */ 716 public ByteStringBuffer insert(final int pos, final ByteString b) 717 throws NullPointerException, IndexOutOfBoundsException 718 { 719 if (b == null) 720 { 721 final NullPointerException e = 722 new NullPointerException(ERR_BS_BUFFER_BYTE_STRING_NULL.get()); 723 Debug.debugCodingError(e); 724 throw e; 725 } 726 727 return insert(pos, b.getValue()); 728 } 729 730 731 732 /** 733 * Inserts the provided byte string buffer into this buffer at the specified 734 * position. 735 * 736 * @param pos The position at which the data is to be inserted. 737 * @param buffer The buffer whose contents should be inserted into this 738 * buffer. 739 * 740 * @return A reference to this buffer. 741 * 742 * @throws NullPointerException If the provided buffer is {@code null}. 743 * 744 * @throws IndexOutOfBoundsException If the specified position is negative 745 * or greater than the current length. 746 */ 747 public ByteStringBuffer insert(final int pos, final ByteStringBuffer buffer) 748 throws NullPointerException, IndexOutOfBoundsException 749 { 750 if (buffer == null) 751 { 752 final NullPointerException e = 753 new NullPointerException(ERR_BS_BUFFER_BUFFER_NULL.get()); 754 Debug.debugCodingError(e); 755 throw e; 756 } 757 758 return insert(pos, buffer.array, 0, buffer.endPos); 759 } 760 761 762 763 /** 764 * Inserts the provided character into this buffer at the provided position. 765 * 766 * @param pos The position at which the character is to be inserted. 767 * @param c The character to be inserted into this buffer. 768 * 769 * @return A reference to this buffer. 770 * 771 * @throws IndexOutOfBoundsException If the specified position is negative 772 * or greater than the current length. 773 */ 774 public ByteStringBuffer insert(final int pos, final char c) 775 throws IndexOutOfBoundsException 776 { 777 if ((pos < 0) || (pos > endPos)) 778 { 779 final String message; 780 if (pos < 0) 781 { 782 message = ERR_BS_BUFFER_POS_NEGATIVE.get(pos); 783 } 784 else 785 { 786 message = ERR_BS_BUFFER_POS_TOO_LARGE.get(pos, endPos); 787 } 788 789 final IndexOutOfBoundsException e = 790 new IndexOutOfBoundsException(message); 791 Debug.debugCodingError(e); 792 throw e; 793 } 794 else if (pos == endPos) 795 { 796 return append(c); 797 } 798 799 final byte b = (byte) (c & 0x7F); 800 if (b == c) 801 { 802 ensureCapacity(endPos + 1); 803 System.arraycopy(array, pos, array, pos+1, (endPos-pos)); 804 array[pos] = b; 805 endPos++; 806 } 807 else 808 { 809 insert(pos, String.valueOf(c)); 810 } 811 812 return this; 813 } 814 815 816 817 /** 818 * Inserts the contents of the provided character array into this buffer at 819 * the specified position. 820 * 821 * @param pos The position at which the data is to be inserted. 822 * @param c The array whose contents should be inserted into this buffer. 823 * 824 * @return A reference to this buffer. 825 * 826 * @throws NullPointerException If the provided array is {@code null}. 827 * 828 * @throws IndexOutOfBoundsException If the specified position is negative 829 * or greater than the current length. 830 */ 831 public ByteStringBuffer insert(final int pos, final char[] c) 832 throws NullPointerException, IndexOutOfBoundsException 833 { 834 if (c == null) 835 { 836 final NullPointerException e = 837 new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get()); 838 Debug.debugCodingError(e); 839 throw e; 840 } 841 842 return insert(pos, new String(c, 0, c.length)); 843 } 844 845 846 847 /** 848 * Inserts the specified portion of the provided character array to this 849 * buffer at the specified position. 850 * 851 * @param pos The position at which the data is to be inserted. 852 * @param c The array whose contents should be inserted into this buffer. 853 * @param off The offset within the array at which to begin copying data. 854 * @param len The number of characters to copy. 855 * 856 * @return A reference to this buffer. 857 * 858 * @throws NullPointerException If the provided array is {@code null}. 859 * 860 * @throws IndexOutOfBoundsException If the specified position is negative 861 * or greater than the current length, if 862 * the offset or length are negative, if 863 * the offset plus the length is beyond 864 * the end of the provided array. 865 */ 866 public ByteStringBuffer insert(final int pos, final char[] c, final int off, 867 final int len) 868 throws NullPointerException, IndexOutOfBoundsException 869 { 870 if (c == null) 871 { 872 final NullPointerException e = 873 new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get()); 874 Debug.debugCodingError(e); 875 throw e; 876 } 877 878 return insert(pos, new String(c, off, len)); 879 } 880 881 882 883 /** 884 * Inserts the provided character sequence to this buffer at the specified 885 * position. 886 * 887 * @param pos The position at which the data is to be inserted. 888 * @param s The character sequence to insert into this buffer. 889 * 890 * @return A reference to this buffer. 891 * 892 * @throws NullPointerException If the provided character sequence is 893 * {@code null}. 894 * 895 * @throws IndexOutOfBoundsException If the specified position is negative 896 * or greater than the current length. 897 */ 898 public ByteStringBuffer insert(final int pos, final CharSequence s) 899 throws NullPointerException, IndexOutOfBoundsException 900 { 901 if (s == null) 902 { 903 final NullPointerException e = 904 new NullPointerException(ERR_BS_BUFFER_CHAR_SEQUENCE_NULL.get()); 905 Debug.debugCodingError(e); 906 throw e; 907 } 908 909 if ((pos < 0) || (pos > endPos)) 910 { 911 final String message; 912 if (pos < 0) 913 { 914 message = ERR_BS_BUFFER_POS_NEGATIVE.get(pos); 915 } 916 else 917 { 918 message = ERR_BS_BUFFER_POS_TOO_LARGE.get(pos, endPos); 919 } 920 921 final IndexOutOfBoundsException e = 922 new IndexOutOfBoundsException(message); 923 Debug.debugCodingError(e); 924 throw e; 925 } 926 else if (pos == endPos) 927 { 928 return append(s); 929 } 930 else 931 { 932 return insert(pos, StaticUtils.getBytes(s.toString())); 933 } 934 } 935 936 937 938 /** 939 * Inserts the provided integer value to this buffer. 940 * 941 * @param pos The position at which the value is to be inserted. 942 * @param i The integer value to be inserted into this buffer. 943 * 944 * @return A reference to this buffer. 945 * 946 * @throws IndexOutOfBoundsException If the specified position is negative 947 * or greater than the current length. 948 */ 949 public ByteStringBuffer insert(final int pos, final int i) 950 throws IndexOutOfBoundsException 951 { 952 final int length = getBytes(i); 953 return insert(pos, TEMP_NUMBER_BUFFER.get(), 0, length); 954 } 955 956 957 958 /** 959 * Inserts the provided long value to this buffer. 960 * 961 * @param pos The position at which the value is to be inserted. 962 * @param l The long value to be inserted into this buffer. 963 * 964 * @return A reference to this buffer. 965 * 966 * @throws IndexOutOfBoundsException If the specified position is negative 967 * or greater than the current length. 968 */ 969 public ByteStringBuffer insert(final int pos, final long l) 970 throws IndexOutOfBoundsException 971 { 972 final int length = getBytes(l); 973 return insert(pos, TEMP_NUMBER_BUFFER.get(), 0, length); 974 } 975 976 977 978 /** 979 * Deletes the specified number of bytes from the beginning of the buffer. 980 * 981 * @param len The number of bytes to delete. 982 * 983 * @return A reference to this buffer. 984 * 985 * @throws IndexOutOfBoundsException If the specified length is negative, 986 * or if it is greater than the number of 987 * bytes currently contained in this 988 * buffer. 989 */ 990 public ByteStringBuffer delete(final int len) 991 throws IndexOutOfBoundsException 992 { 993 return delete(0, len); 994 } 995 996 997 998 /** 999 * Deletes the indicated number of bytes from the specified location in the 1000 * buffer. 1001 * 1002 * @param off The position in the buffer at which the content to delete 1003 * begins. 1004 * @param len The number of bytes to remove from the buffer. 1005 * 1006 * @return A reference to this buffer. 1007 * 1008 * @throws IndexOutOfBoundsException If the offset or length is negative, or 1009 * if the combination of the offset and 1010 * length is greater than the end of the 1011 * content in the buffer. 1012 */ 1013 public ByteStringBuffer delete(final int off, final int len) 1014 throws IndexOutOfBoundsException 1015 { 1016 if (off < 0) 1017 { 1018 throw new IndexOutOfBoundsException( 1019 ERR_BS_BUFFER_OFFSET_NEGATIVE.get(off)); 1020 } 1021 else if (len < 0) 1022 { 1023 throw new IndexOutOfBoundsException( 1024 ERR_BS_BUFFER_LENGTH_NEGATIVE.get(len)); 1025 } 1026 else if ((off + len) > endPos) 1027 { 1028 throw new IndexOutOfBoundsException( 1029 ERR_BS_BUFFER_OFFSET_PLUS_LENGTH_TOO_LARGE.get(off, len, endPos)); 1030 } 1031 else if (len == 0) 1032 { 1033 return this; 1034 } 1035 else if (off == 0) 1036 { 1037 if (len == endPos) 1038 { 1039 endPos = 0; 1040 return this; 1041 } 1042 else 1043 { 1044 final int newEndPos = endPos - len; 1045 System.arraycopy(array, len, array, 0, newEndPos); 1046 endPos = newEndPos; 1047 return this; 1048 } 1049 } 1050 else 1051 { 1052 if ((off + len) == endPos) 1053 { 1054 endPos = off; 1055 return this; 1056 } 1057 else 1058 { 1059 final int bytesToCopy = endPos - (off+len); 1060 System.arraycopy(array, (off+len), array, off, bytesToCopy); 1061 endPos -= len; 1062 return this; 1063 } 1064 } 1065 } 1066 1067 1068 1069 /** 1070 * Sets the contents of this buffer to include only the provided boolean 1071 * value. 1072 * 1073 * @param b The boolean value to use as the content for this buffer. 1074 * 1075 * @return A reference to this buffer. 1076 */ 1077 public ByteStringBuffer set(final boolean b) 1078 { 1079 if (b) 1080 { 1081 return set(TRUE_VALUE_BYTES, 0, 4); 1082 } 1083 else 1084 { 1085 return set(FALSE_VALUE_BYTES, 0, 5); 1086 } 1087 } 1088 1089 1090 1091 /** 1092 * Sets the contents of this buffer to include only the provided byte. 1093 * 1094 * @param b The byte to use as the content for this buffer. 1095 * 1096 * @return A reference to this buffer. 1097 */ 1098 public ByteStringBuffer set(final byte b) 1099 { 1100 endPos = 0; 1101 return append(b); 1102 } 1103 1104 1105 1106 /** 1107 * Sets the contents of this buffer to the contents of the provided byte 1108 * array. 1109 * 1110 * @param b The byte array containing the content to use for this buffer. 1111 * 1112 * @throws NullPointerException If the provided array is {@code null}. 1113 * 1114 * @return A reference to this buffer. 1115 */ 1116 public ByteStringBuffer set(final byte[] b) 1117 throws NullPointerException 1118 { 1119 if (b == null) 1120 { 1121 final NullPointerException e = 1122 new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get()); 1123 Debug.debugCodingError(e); 1124 throw e; 1125 } 1126 1127 endPos = 0; 1128 return append(b, 0, b.length); 1129 } 1130 1131 1132 1133 /** 1134 * Sets the contents of this buffer to the specified portion of the provided 1135 * byte array. 1136 * 1137 * @param b The byte array containing the content to use for this buffer. 1138 * @param off The offset within the array at which to begin copying data. 1139 * @param len The number of bytes to copy. 1140 * 1141 * @return A reference to this buffer. 1142 * 1143 * @throws NullPointerException If the provided array is {@code null}. 1144 * 1145 * @throws IndexOutOfBoundsException If the offset or length are negative, 1146 * if the offset plus the length is beyond 1147 * the end of the provided array. 1148 */ 1149 public ByteStringBuffer set(final byte[] b, final int off, final int len) 1150 throws NullPointerException, IndexOutOfBoundsException 1151 { 1152 if (b == null) 1153 { 1154 final NullPointerException e = 1155 new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get()); 1156 Debug.debugCodingError(e); 1157 throw e; 1158 } 1159 1160 if ((off < 0) || (len < 0) || (off+len > b.length)) 1161 { 1162 final String message; 1163 if (off < 0) 1164 { 1165 message = ERR_BS_BUFFER_OFFSET_NEGATIVE.get(off); 1166 } 1167 else if (len < 0) 1168 { 1169 message = ERR_BS_BUFFER_LENGTH_NEGATIVE.get(len); 1170 } 1171 else 1172 { 1173 message = ERR_BS_BUFFER_OFFSET_PLUS_LENGTH_TOO_LARGE.get(off, len, 1174 b.length); 1175 } 1176 1177 final IndexOutOfBoundsException e = 1178 new IndexOutOfBoundsException(message); 1179 Debug.debugCodingError(e); 1180 throw e; 1181 } 1182 1183 endPos = 0; 1184 return append(b, off, len); 1185 } 1186 1187 1188 1189 /** 1190 * Sets the contents of this buffer to the contents of the provided byte 1191 * string. 1192 * 1193 * @param b The byte string that should be used as the content for this 1194 * buffer. 1195 * 1196 * @throws NullPointerException If the provided byte string is {@code null}. 1197 * 1198 * @return A reference to this buffer. 1199 */ 1200 public ByteStringBuffer set(final ByteString b) 1201 throws NullPointerException 1202 { 1203 if (b == null) 1204 { 1205 final NullPointerException e = 1206 new NullPointerException(ERR_BS_BUFFER_BYTE_STRING_NULL.get()); 1207 Debug.debugCodingError(e); 1208 throw e; 1209 } 1210 1211 endPos = 0; 1212 b.appendValueTo(this); 1213 return this; 1214 } 1215 1216 1217 1218 /** 1219 * Sets the contents of this buffer to the contents of the provided byte 1220 * string buffer. 1221 * 1222 * @param buffer The buffer whose contents should be used as the content for 1223 * this buffer. 1224 * 1225 * @throws NullPointerException If the provided buffer is {@code null}. 1226 * 1227 * @return A reference to this buffer. 1228 */ 1229 public ByteStringBuffer set(final ByteStringBuffer buffer) 1230 throws NullPointerException 1231 { 1232 if (buffer == null) 1233 { 1234 final NullPointerException e = 1235 new NullPointerException(ERR_BS_BUFFER_BUFFER_NULL.get()); 1236 Debug.debugCodingError(e); 1237 throw e; 1238 } 1239 1240 endPos = 0; 1241 return append(buffer.array, 0, buffer.endPos); 1242 } 1243 1244 1245 1246 /** 1247 * Sets the contents of this buffer to include only the provided character. 1248 * 1249 * @param c The character use as the content for this buffer. 1250 * 1251 * @return A reference to this buffer. 1252 */ 1253 public ByteStringBuffer set(final char c) 1254 { 1255 endPos = 0; 1256 return append(c); 1257 } 1258 1259 1260 1261 /** 1262 * Sets the contents of this buffer to the contents of the provided character 1263 * array. 1264 * 1265 * @param c The character array containing the content to use for this 1266 * buffer. 1267 * 1268 * @throws NullPointerException If the provided array is {@code null}. 1269 * 1270 * @return A reference to this buffer. 1271 */ 1272 public ByteStringBuffer set(final char[] c) 1273 throws NullPointerException 1274 { 1275 if (c == null) 1276 { 1277 final NullPointerException e = 1278 new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get()); 1279 Debug.debugCodingError(e); 1280 throw e; 1281 } 1282 1283 endPos = 0; 1284 return append(c, 0, c.length); 1285 } 1286 1287 1288 1289 /** 1290 * Sets the contents of this buffer to the specified portion of the provided 1291 * character array. 1292 * 1293 * @param c The character array containing the content to use for this 1294 * buffer. 1295 * @param off The offset within the array at which to begin copying data. 1296 * @param len The number of characters to copy. 1297 * 1298 * @return A reference to this buffer. 1299 * 1300 * @throws NullPointerException If the provided array is {@code null}. 1301 * 1302 * @throws IndexOutOfBoundsException If the offset or length are negative, 1303 * if the offset plus the length is beyond 1304 * the end of the provided array. 1305 */ 1306 public ByteStringBuffer set(final char[] c, final int off, final int len) 1307 throws NullPointerException, IndexOutOfBoundsException 1308 { 1309 if (c == null) 1310 { 1311 final NullPointerException e = 1312 new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get()); 1313 Debug.debugCodingError(e); 1314 throw e; 1315 } 1316 1317 if ((off < 0) || (len < 0) || (off+len > c.length)) 1318 { 1319 final String message; 1320 if (off < 0) 1321 { 1322 message = ERR_BS_BUFFER_OFFSET_NEGATIVE.get(off); 1323 } 1324 else if (len < 0) 1325 { 1326 message = ERR_BS_BUFFER_LENGTH_NEGATIVE.get(len); 1327 } 1328 else 1329 { 1330 message = ERR_BS_BUFFER_OFFSET_PLUS_LENGTH_TOO_LARGE.get(off, len, 1331 c.length); 1332 } 1333 1334 final IndexOutOfBoundsException e = 1335 new IndexOutOfBoundsException(message); 1336 Debug.debugCodingError(e); 1337 throw e; 1338 } 1339 1340 endPos = 0; 1341 return append(c, off, len); 1342 } 1343 1344 1345 1346 /** 1347 * Sets the contents of this buffer to the specified portion of the provided 1348 * character sequence. 1349 * 1350 * @param s The character sequence to use as the content for this buffer. 1351 * 1352 * @throws NullPointerException If the provided character sequence is 1353 * {@code null}. 1354 * 1355 * @return A reference to this buffer. 1356 */ 1357 public ByteStringBuffer set(final CharSequence s) 1358 throws NullPointerException 1359 { 1360 if (s == null) 1361 { 1362 final NullPointerException e = 1363 new NullPointerException(ERR_BS_BUFFER_CHAR_SEQUENCE_NULL.get()); 1364 Debug.debugCodingError(e); 1365 throw e; 1366 } 1367 1368 endPos = 0; 1369 return append(s); 1370 } 1371 1372 1373 1374 /** 1375 * Sets the contents of this buffer to include only the provided integer 1376 * value. 1377 * 1378 * @param i The integer value to use as the content for this buffer. 1379 * 1380 * @return A reference to this buffer. 1381 */ 1382 public ByteStringBuffer set(final int i) 1383 { 1384 final int length = getBytes(i); 1385 return set(TEMP_NUMBER_BUFFER.get(), 0, length); 1386 } 1387 1388 1389 1390 /** 1391 * Sets the contents of this buffer to include only the provided long value. 1392 * 1393 * @param l The long value to use as the content for this buffer. 1394 * 1395 * @return A reference to this buffer. 1396 */ 1397 public ByteStringBuffer set(final long l) 1398 { 1399 final int length = getBytes(l); 1400 return set(TEMP_NUMBER_BUFFER.get(), 0, length); 1401 } 1402 1403 1404 1405 /** 1406 * Clears the contents of this buffer. 1407 * 1408 * @return A reference to this buffer. 1409 */ 1410 public ByteStringBuffer clear() 1411 { 1412 endPos = 0; 1413 return this; 1414 } 1415 1416 1417 1418 /** 1419 * Clears the contents of this buffer. 1420 * 1421 * @param zero Indicates whether to overwrite the content of the backing 1422 * array with all zeros in order to wipe out any sensitive data 1423 * it may contain. 1424 * 1425 * @return A reference to this buffer. 1426 */ 1427 public ByteStringBuffer clear(final boolean zero) 1428 { 1429 endPos = 0; 1430 1431 if (zero) 1432 { 1433 Arrays.fill(array, (byte) 0x00); 1434 } 1435 1436 return this; 1437 } 1438 1439 1440 1441 /** 1442 * Retrieves the current backing array for this buffer. The data will begin 1443 * at position 0 and will contain {@link ByteStringBuffer#length} bytes. 1444 * 1445 * @return The current backing array for this buffer. 1446 */ 1447 public byte[] getBackingArray() 1448 { 1449 return array; 1450 } 1451 1452 1453 1454 /** 1455 * Indicates whether this buffer is currently empty. 1456 * 1457 * @return {@code true} if this buffer is currently empty, or {@code false} 1458 * if not. 1459 */ 1460 public boolean isEmpty() 1461 { 1462 return (endPos == 0); 1463 } 1464 1465 1466 1467 /** 1468 * Retrieves the number of bytes contained in this buffer. 1469 * 1470 * @return The number of bytes contained in this buffer. 1471 */ 1472 public int length() 1473 { 1474 return endPos; 1475 } 1476 1477 1478 1479 /** 1480 * Sets the length of this buffer to the specified value. If the new length 1481 * is greater than the current length, the value will be padded with zeroes. 1482 * 1483 * @param length The new length to use for the buffer. It must be greater 1484 * than or equal to zero. 1485 * 1486 * @throws IndexOutOfBoundsException If the provided length is negative. 1487 */ 1488 public void setLength(final int length) 1489 throws IndexOutOfBoundsException 1490 { 1491 if (length < 0) 1492 { 1493 final IndexOutOfBoundsException e = new IndexOutOfBoundsException( 1494 ERR_BS_BUFFER_LENGTH_NEGATIVE.get(length)); 1495 Debug.debugCodingError(e); 1496 throw e; 1497 } 1498 1499 if (length > endPos) 1500 { 1501 ensureCapacity(length); 1502 Arrays.fill(array, endPos, length, (byte) 0x00); 1503 endPos = length; 1504 } 1505 else 1506 { 1507 endPos = length; 1508 } 1509 } 1510 1511 1512 1513 /** 1514 * Returns the current capacity for this buffer. 1515 * 1516 * @return The current capacity for this buffer. 1517 */ 1518 public int capacity() 1519 { 1520 return capacity; 1521 } 1522 1523 1524 1525 /** 1526 * Ensures that the total capacity of this buffer is at least equal to the 1527 * specified size. 1528 * 1529 * @param minimumCapacity The minimum capacity for this buffer. 1530 */ 1531 public void ensureCapacity(final int minimumCapacity) 1532 { 1533 if (capacity < minimumCapacity) 1534 { 1535 final int newCapacity = Math.max(minimumCapacity, (2 * capacity) + 2); 1536 final byte[] newArray = new byte[newCapacity]; 1537 System.arraycopy(array, 0, newArray, 0, capacity); 1538 array = newArray; 1539 capacity = newCapacity; 1540 } 1541 } 1542 1543 1544 1545 /** 1546 * Sets the capacity equal to the specified value. If the provided capacity 1547 * is less than the current length, then the length will be reduced to the 1548 * new capacity. 1549 * 1550 * @param capacity The new capacity for this buffer. It must be greater 1551 * than or equal to zero. 1552 * 1553 * @throws IndexOutOfBoundsException If the provided capacity is negative. 1554 */ 1555 public void setCapacity(final int capacity) 1556 throws IndexOutOfBoundsException 1557 { 1558 if (capacity < 0) 1559 { 1560 final IndexOutOfBoundsException e = new IndexOutOfBoundsException( 1561 ERR_BS_BUFFER_CAPACITY_NEGATIVE.get(capacity)); 1562 Debug.debugCodingError(e); 1563 throw e; 1564 } 1565 1566 if (this.capacity == capacity) 1567 { 1568 return; 1569 } 1570 else if (this.capacity < capacity) 1571 { 1572 final byte[] newArray = new byte[capacity]; 1573 System.arraycopy(array, 0, newArray, 0, this.capacity); 1574 array = newArray; 1575 this.capacity = capacity; 1576 } 1577 else 1578 { 1579 final byte[] newArray = new byte[capacity]; 1580 System.arraycopy(array, 0, newArray, 0, capacity); 1581 array = newArray; 1582 endPos = Math.min(endPos, capacity); 1583 this.capacity = capacity; 1584 } 1585 } 1586 1587 1588 1589 /** 1590 * Trims the backing array to the minimal size required for this buffer. 1591 * 1592 * @return A reference to this buffer. 1593 */ 1594 public ByteStringBuffer trimToSize() 1595 { 1596 if (endPos != capacity) 1597 { 1598 final byte[] newArray = new byte[endPos]; 1599 System.arraycopy(array, 0, newArray, 0, endPos); 1600 array = newArray; 1601 capacity = endPos; 1602 } 1603 1604 return this; 1605 } 1606 1607 1608 1609 /** 1610 * Returns a new byte array with the content from this buffer. 1611 * 1612 * @return A byte array containing the content from this buffer. 1613 */ 1614 public byte[] toByteArray() 1615 { 1616 final byte[] newArray = new byte[endPos]; 1617 System.arraycopy(array, 0, newArray, 0, endPos); 1618 return newArray; 1619 } 1620 1621 1622 1623 /** 1624 * Returns a new byte string with the content from this buffer. 1625 * 1626 * @return A byte string with the content from this buffer. 1627 */ 1628 public ByteString toByteString() 1629 { 1630 return new ASN1OctetString(toByteArray()); 1631 } 1632 1633 1634 1635 /** 1636 * Creates an input stream that may be used to read content from this buffer. 1637 * This buffer should not be altered while the input stream is being used. 1638 * 1639 * @return An input stream that may be used to read content from this buffer. 1640 */ 1641 public InputStream asInputStream() 1642 { 1643 return new ByteArrayInputStream(array, 0, endPos); 1644 } 1645 1646 1647 1648 /** 1649 * Writes the contents of this byte string buffer to the provided output 1650 * stream. 1651 * 1652 * @param outputStream The output stream to which the data should be 1653 * written. 1654 * 1655 * @throws IOException If a problem occurs while writing to the provided 1656 * output stream. 1657 */ 1658 public void write(final OutputStream outputStream) 1659 throws IOException 1660 { 1661 outputStream.write(array, 0, endPos); 1662 } 1663 1664 1665 1666 /** 1667 * Adds the bytes comprising the string representation of the provided long 1668 * value to the temporary number buffer. 1669 * 1670 * @param l The long value to be appended. 1671 * 1672 * @return The number of bytes in the string representation of the value. 1673 */ 1674 private static int getBytes(final long l) 1675 { 1676 // NOTE: This method is probably not as efficient as it could be, but it is 1677 // more important to avoid the need for memory allocation. 1678 byte[] b = TEMP_NUMBER_BUFFER.get(); 1679 if (b == null) 1680 { 1681 b = new byte[20]; 1682 TEMP_NUMBER_BUFFER.set(b); 1683 } 1684 1685 if (l == Long.MIN_VALUE) 1686 { 1687 b[0] = '-'; 1688 b[1] = '9'; 1689 b[2] = '2'; 1690 b[3] = '2'; 1691 b[4] = '3'; 1692 b[5] = '3'; 1693 b[6] = '7'; 1694 b[7] = '2'; 1695 b[8] = '0'; 1696 b[9] = '3'; 1697 b[10] = '6'; 1698 b[11] = '8'; 1699 b[12] = '5'; 1700 b[13] = '4'; 1701 b[14] = '7'; 1702 b[15] = '7'; 1703 b[16] = '5'; 1704 b[17] = '8'; 1705 b[18] = '0'; 1706 b[19] = '8'; 1707 return 20; 1708 } 1709 else if (l == 0L) 1710 { 1711 b[0] = '0'; 1712 return 1; 1713 } 1714 1715 int pos = 0; 1716 long v = l; 1717 if (l < 0) 1718 { 1719 b[0] = '-'; 1720 pos = 1; 1721 v = Math.abs(l); 1722 } 1723 1724 long divisor; 1725 if (v <= 9L) 1726 { 1727 divisor = 1L; 1728 } 1729 else if (v <= 99L) 1730 { 1731 divisor = 10L; 1732 } 1733 else if (v <= 999L) 1734 { 1735 divisor = 100L; 1736 } 1737 else if (v <= 9999L) 1738 { 1739 divisor = 1000L; 1740 } 1741 else if (v <= 99_999L) 1742 { 1743 divisor = 10_000L; 1744 } 1745 else if (v <= 999_999L) 1746 { 1747 divisor = 100_000L; 1748 } 1749 else if (v <= 9_999_999L) 1750 { 1751 divisor = 1_000_000L; 1752 } 1753 else if (v <= 99_999_999L) 1754 { 1755 divisor = 10_000_000L; 1756 } 1757 else if (v <= 999_999_999L) 1758 { 1759 divisor = 100_000_000L; 1760 } 1761 else if (v <= 9_999_999_999L) 1762 { 1763 divisor = 1_000_000_000L; 1764 } 1765 else if (v <= 99_999_999_999L) 1766 { 1767 divisor = 10_000_000_000L; 1768 } 1769 else if (v <= 999_999_999_999L) 1770 { 1771 divisor = 100_000_000_000L; 1772 } 1773 else if (v <= 9_999_999_999_999L) 1774 { 1775 divisor = 1_000_000_000_000L; 1776 } 1777 else if (v <= 99_999_999_999_999L) 1778 { 1779 divisor = 10_000_000_000_000L; 1780 } 1781 else if (v <= 999_999_999_999_999L) 1782 { 1783 divisor = 100_000_000_000_000L; 1784 } 1785 else if (v <= 9_999_999_999_999_999L) 1786 { 1787 divisor = 1_000_000_000_000_000L; 1788 } 1789 else if (v <= 99_999_999_999_999_999L) 1790 { 1791 divisor = 10_000_000_000_000_000L; 1792 } 1793 else if (v <= 999_999_999_999_999_999L) 1794 { 1795 divisor = 100_000_000_000_000_000L; 1796 } 1797 else 1798 { 1799 divisor = 1_000_000_000_000_000_000L; 1800 } 1801 1802 while (true) 1803 { 1804 final long digit = v / divisor; 1805 switch ((int) digit) 1806 { 1807 case 0: 1808 b[pos++] = '0'; 1809 break; 1810 case 1: 1811 b[pos++] = '1'; 1812 break; 1813 case 2: 1814 b[pos++] = '2'; 1815 break; 1816 case 3: 1817 b[pos++] = '3'; 1818 break; 1819 case 4: 1820 b[pos++] = '4'; 1821 break; 1822 case 5: 1823 b[pos++] = '5'; 1824 break; 1825 case 6: 1826 b[pos++] = '6'; 1827 break; 1828 case 7: 1829 b[pos++] = '7'; 1830 break; 1831 case 8: 1832 b[pos++] = '8'; 1833 break; 1834 case 9: 1835 b[pos++] = '9'; 1836 break; 1837 } 1838 1839 if (divisor == 1L) 1840 { 1841 break; 1842 } 1843 else 1844 { 1845 v -= (divisor * digit); 1846 if (v == 0) 1847 { 1848 while (divisor > 1L) 1849 { 1850 b[pos++] = '0'; 1851 divisor /= 10L; 1852 } 1853 1854 break; 1855 } 1856 1857 divisor /= 10L; 1858 } 1859 } 1860 1861 return pos; 1862 } 1863 1864 1865 1866 /** 1867 * Retrieves a hash code for this byte array. 1868 * 1869 * @return A hash code for this byte array. 1870 */ 1871 @Override() 1872 public int hashCode() 1873 { 1874 int hashCode = 0; 1875 1876 for (int i=0; i < endPos; i++) 1877 { 1878 hashCode += array[i]; 1879 } 1880 1881 return hashCode; 1882 } 1883 1884 1885 1886 /** 1887 * Indicates whether the provided object is a byte string buffer with contents 1888 * that are identical to that of this buffer. 1889 * 1890 * @param o The object for which to make the determination. 1891 * 1892 * @return {@code true} if the provided object is considered equal to this 1893 * buffer, or {@code false} if not. 1894 */ 1895 @Override() 1896 public boolean equals(final Object o) 1897 { 1898 if (o == null) 1899 { 1900 return false; 1901 } 1902 1903 if (o == this) 1904 { 1905 return true; 1906 } 1907 1908 if (! (o instanceof ByteStringBuffer)) 1909 { 1910 return false; 1911 } 1912 1913 final ByteStringBuffer b = (ByteStringBuffer) o; 1914 if (endPos != b.endPos) 1915 { 1916 return false; 1917 } 1918 1919 for (int i=0; i < endPos; i++) 1920 { 1921 if (array[i] != b.array[i]) 1922 { 1923 return false; 1924 } 1925 } 1926 1927 return true; 1928 } 1929 1930 1931 1932 /** 1933 * Creates a duplicate of this byte string buffer. It will have identical 1934 * content but with a different backing array. Changes to this byte string 1935 * buffer will not impact the duplicate, and vice-versa. 1936 * 1937 * @return A duplicate of this byte string buffer. 1938 */ 1939 public ByteStringBuffer duplicate() 1940 { 1941 final ByteStringBuffer newBuffer = new ByteStringBuffer(endPos); 1942 return newBuffer.append(this); 1943 } 1944 1945 1946 1947 /** 1948 * Retrieves a string representation of the contents for this buffer. 1949 * 1950 * @return A string representation of the contents for this buffer. 1951 */ 1952 @Override() 1953 public String toString() 1954 { 1955 return StaticUtils.toUTF8String(array, 0, endPos); 1956 } 1957}