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