001/* 002 * Copyright 2008-2014 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2014 UnboundID Corp. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 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 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 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 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 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 append(String.valueOf(c, pos, (off + len - pos))); 412 break; 413 } 414 } 415 } 416 417 return this; 418 } 419 420 421 422 /** 423 * Appends the provided character sequence to this buffer. 424 * 425 * @param s The character sequence to append to this buffer. 426 * 427 * @return A reference to this buffer. 428 * 429 * @throws NullPointerException If the provided character sequence is 430 * {@code null}. 431 */ 432 public ByteStringBuffer append(final CharSequence s) 433 throws NullPointerException 434 { 435 return append(s, 0, s.length()); 436 } 437 438 439 440 /** 441 * Appends the provided character sequence to this buffer. 442 * 443 * @param s The character sequence to append to this buffer. 444 * @param start The position in the sequence of the first character in the 445 * sequence to be appended to this buffer. 446 * @param end The position in the sequence immediately after the position 447 * of the last character to be appended. 448 * 449 * @return A reference to this buffer. 450 * 451 * @throws NullPointerException If the provided character sequence is 452 * {@code null}. 453 * 454 * @throws IndexOutOfBoundsException If the provided start or end positions 455 * are outside the bounds of the given 456 * character sequence. 457 */ 458 public ByteStringBuffer append(final CharSequence s, final int start, 459 final int end) 460 throws NullPointerException, IndexOutOfBoundsException 461 { 462 if (s == null) 463 { 464 final NullPointerException e = 465 new NullPointerException(ERR_BS_BUFFER_CHAR_SEQUENCE_NULL.get()); 466 debugCodingError(e); 467 throw e; 468 } 469 470 final int length = end - start; 471 ensureCapacity(endPos + length); 472 for (int i=start; i < end; i++) 473 { 474 final char c = s.charAt(i); 475 final byte b = (byte) (c & 0x7F); 476 if (b == c) 477 { 478 array[endPos++] = b; 479 } 480 else 481 { 482 append(StaticUtils.getBytes(s.subSequence(i, length).toString())); 483 break; 484 } 485 } 486 487 return this; 488 } 489 490 491 492 /** 493 * Appends the provided integer value to this buffer. 494 * 495 * @param i The integer value to be appended to this buffer. 496 * 497 * @return A reference to this buffer. 498 */ 499 public ByteStringBuffer append(final int i) 500 { 501 final int length = getBytes(i); 502 return append(TEMP_NUMBER_BUFFER.get(), 0, length); 503 } 504 505 506 507 /** 508 * Appends the provided long value to this buffer. 509 * 510 * @param l The long value to be appended to this buffer. 511 * 512 * @return A reference to this buffer. 513 */ 514 public ByteStringBuffer append(final long l) 515 { 516 final int length = getBytes(l); 517 return append(TEMP_NUMBER_BUFFER.get(), 0, length); 518 } 519 520 521 522 /** 523 * Inserts the provided boolean value to this buffer. 524 * 525 * @param pos The position at which the value is to be inserted. 526 * @param b The boolean value to be inserted into this buffer. 527 * 528 * @return A reference to this buffer. 529 * 530 * @throws IndexOutOfBoundsException If the specified position is negative 531 * or greater than the current length. 532 */ 533 public ByteStringBuffer insert(final int pos, final boolean b) 534 throws IndexOutOfBoundsException 535 { 536 if (b) 537 { 538 return insert(pos, TRUE_VALUE_BYTES, 0, 4); 539 } 540 else 541 { 542 return insert(pos, FALSE_VALUE_BYTES, 0, 5); 543 } 544 } 545 546 547 548 /** 549 * Inserts the provided byte at the specified position in this buffer. 550 * 551 * @param pos The position at which the byte is to be inserted. 552 * @param b The byte to be inserted into this buffer. 553 * 554 * @return A reference to this buffer. 555 * 556 * @throws IndexOutOfBoundsException If the specified position is negative 557 * or greater than the current length. 558 */ 559 public ByteStringBuffer insert(final int pos, final byte b) 560 throws IndexOutOfBoundsException 561 { 562 if ((pos < 0) || (pos > endPos)) 563 { 564 final String message; 565 if (pos < 0) 566 { 567 message = ERR_BS_BUFFER_POS_NEGATIVE.get(pos); 568 } 569 else 570 { 571 message = ERR_BS_BUFFER_POS_TOO_LARGE.get(pos, endPos); 572 } 573 574 final IndexOutOfBoundsException e = 575 new IndexOutOfBoundsException(message); 576 debugCodingError(e); 577 throw e; 578 } 579 else if (pos == endPos) 580 { 581 return append(b); 582 } 583 584 ensureCapacity(endPos + 1); 585 System.arraycopy(array, pos, array, pos+1, (endPos-pos)); 586 array[pos] = b; 587 endPos++; 588 return this; 589 } 590 591 592 593 /** 594 * Inserts the contents of the provided byte array at the specified position 595 * in this buffer. 596 * 597 * @param pos The position at which the data is to be inserted. 598 * @param b The array whose contents should be inserted into this buffer. 599 * 600 * @return A reference to this buffer. 601 * 602 * @throws NullPointerException If the provided array is {@code null}. 603 * 604 * @throws IndexOutOfBoundsException If the specified position is negative 605 * or greater than the current length. 606 */ 607 public ByteStringBuffer insert(final int pos, final byte[] b) 608 throws NullPointerException, IndexOutOfBoundsException 609 { 610 if (b == null) 611 { 612 final NullPointerException e = 613 new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get()); 614 debugCodingError(e); 615 throw e; 616 } 617 618 return insert(pos, b, 0, b.length); 619 } 620 621 622 623 /** 624 * Inserts a portion of the data in the provided array at the specified 625 * position in this buffer. 626 * 627 * Appends the specified portion of the provided byte array to this buffer. 628 * 629 * @param pos The position at which the data is to be inserted. 630 * @param b The array whose contents should be inserted into this buffer. 631 * @param off The offset within the array at which to begin copying data. 632 * @param len The number of bytes to copy. 633 * 634 * @return A reference to this buffer. 635 * 636 * @throws NullPointerException If the provided array is {@code null}. 637 * 638 * @throws IndexOutOfBoundsException If the specified position is negative 639 * or greater than the current length, if 640 * the offset or length are negative, if 641 * the offset plus the length is beyond 642 * the end of the provided array. 643 */ 644 public ByteStringBuffer insert(final int pos, final byte[] b, final int off, 645 final int len) 646 throws NullPointerException, IndexOutOfBoundsException 647 { 648 if (b == null) 649 { 650 final NullPointerException e = 651 new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get()); 652 debugCodingError(e); 653 throw e; 654 } 655 656 if ((pos < 0) || (pos > endPos) || (off < 0) || (len < 0) || 657 (off+len > b.length)) 658 { 659 final String message; 660 if (pos < 0) 661 { 662 message = ERR_BS_BUFFER_POS_NEGATIVE.get(pos); 663 } 664 else if (pos > endPos) 665 { 666 message = ERR_BS_BUFFER_POS_TOO_LARGE.get(pos, endPos); 667 } 668 else if (off < 0) 669 { 670 message = ERR_BS_BUFFER_OFFSET_NEGATIVE.get(off); 671 } 672 else if (len < 0) 673 { 674 message = ERR_BS_BUFFER_LENGTH_NEGATIVE.get(len); 675 } 676 else 677 { 678 message = ERR_BS_BUFFER_OFFSET_PLUS_LENGTH_TOO_LARGE.get(off, len, 679 b.length); 680 } 681 682 final IndexOutOfBoundsException e = 683 new IndexOutOfBoundsException(message); 684 debugCodingError(e); 685 throw e; 686 } 687 else if (len == 0) 688 { 689 return this; 690 } 691 else if (pos == endPos) 692 { 693 return append(b, off, len); 694 } 695 696 ensureCapacity(endPos + len); 697 System.arraycopy(array, pos, array, pos+len, (endPos-pos)); 698 System.arraycopy(b, off, array, pos, len); 699 endPos += len; 700 return this; 701 } 702 703 704 705 /** 706 * Inserts the provided byte string into this buffer at the specified 707 * position. 708 * 709 * @param pos The position at which the data is to be inserted. 710 * @param b The byte string to insert into this buffer. 711 * 712 * @return A reference to this buffer. 713 * 714 * @throws NullPointerException If the provided buffer is {@code null}. 715 * 716 * @throws IndexOutOfBoundsException If the specified position is negative 717 * or greater than the current length. 718 */ 719 public ByteStringBuffer insert(final int pos, final ByteString b) 720 throws NullPointerException, IndexOutOfBoundsException 721 { 722 if (b == null) 723 { 724 final NullPointerException e = 725 new NullPointerException(ERR_BS_BUFFER_BYTE_STRING_NULL.get()); 726 debugCodingError(e); 727 throw e; 728 } 729 730 return insert(pos, b.getValue()); 731 } 732 733 734 735 /** 736 * Inserts the provided byte string buffer into this buffer at the specified 737 * position. 738 * 739 * @param pos The position at which the data is to be inserted. 740 * @param buffer The buffer whose contents should be inserted into this 741 * buffer. 742 * 743 * @return A reference to this buffer. 744 * 745 * @throws NullPointerException If the provided buffer is {@code null}. 746 * 747 * @throws IndexOutOfBoundsException If the specified position is negative 748 * or greater than the current length. 749 */ 750 public ByteStringBuffer insert(final int pos, final ByteStringBuffer buffer) 751 throws NullPointerException, IndexOutOfBoundsException 752 { 753 if (buffer == null) 754 { 755 final NullPointerException e = 756 new NullPointerException(ERR_BS_BUFFER_BUFFER_NULL.get()); 757 debugCodingError(e); 758 throw e; 759 } 760 761 return insert(pos, buffer.array, 0, buffer.endPos); 762 } 763 764 765 766 /** 767 * Inserts the provided character into this buffer at the provided position. 768 * 769 * @param pos The position at which the character is to be inserted. 770 * @param c The character to be inserted into this buffer. 771 * 772 * @return A reference to this buffer. 773 * 774 * @throws IndexOutOfBoundsException If the specified position is negative 775 * or greater than the current length. 776 */ 777 public ByteStringBuffer insert(final int pos, final char c) 778 throws IndexOutOfBoundsException 779 { 780 if ((pos < 0) || (pos > endPos)) 781 { 782 final String message; 783 if (pos < 0) 784 { 785 message = ERR_BS_BUFFER_POS_NEGATIVE.get(pos); 786 } 787 else 788 { 789 message = ERR_BS_BUFFER_POS_TOO_LARGE.get(pos, endPos); 790 } 791 792 final IndexOutOfBoundsException e = 793 new IndexOutOfBoundsException(message); 794 debugCodingError(e); 795 throw e; 796 } 797 else if (pos == endPos) 798 { 799 return append(c); 800 } 801 802 final byte b = (byte) (c & 0x7F); 803 if (b == c) 804 { 805 ensureCapacity(endPos + 1); 806 System.arraycopy(array, pos, array, pos+1, (endPos-pos)); 807 array[pos] = b; 808 endPos++; 809 } 810 else 811 { 812 insert(pos, String.valueOf(c)); 813 } 814 815 return this; 816 } 817 818 819 820 /** 821 * Inserts the contents of the provided character array into this buffer at 822 * the specified position. 823 * 824 * @param pos The position at which the data is to be inserted. 825 * @param c The array whose contents should be inserted into this buffer. 826 * 827 * @return A reference to this buffer. 828 * 829 * @throws NullPointerException If the provided array is {@code null}. 830 * 831 * @throws IndexOutOfBoundsException If the specified position is negative 832 * or greater than the current length. 833 */ 834 public ByteStringBuffer insert(final int pos, final char[] c) 835 throws NullPointerException, IndexOutOfBoundsException 836 { 837 if (c == null) 838 { 839 final NullPointerException e = 840 new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get()); 841 debugCodingError(e); 842 throw e; 843 } 844 845 return insert(pos, new String(c, 0, c.length)); 846 } 847 848 849 850 /** 851 * Inserts the specified portion of the provided character array to this 852 * buffer at the specified position. 853 * 854 * @param pos The position at which the data is to be inserted. 855 * @param c The array whose contents should be inserted into this buffer. 856 * @param off The offset within the array at which to begin copying data. 857 * @param len The number of characters to copy. 858 * 859 * @return A reference to this buffer. 860 * 861 * @throws NullPointerException If the provided array is {@code null}. 862 * 863 * @throws IndexOutOfBoundsException If the specified position is negative 864 * or greater than the current length, if 865 * the offset or length are negative, if 866 * the offset plus the length is beyond 867 * the end of the provided array. 868 */ 869 public ByteStringBuffer insert(final int pos, final char[] c, final int off, 870 final int len) 871 throws NullPointerException, IndexOutOfBoundsException 872 { 873 if (c == null) 874 { 875 final NullPointerException e = 876 new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get()); 877 debugCodingError(e); 878 throw e; 879 } 880 881 return insert(pos, new String(c, off, len)); 882 } 883 884 885 886 /** 887 * Inserts the provided character sequence to this buffer at the specified 888 * position. 889 * 890 * @param pos The position at which the data is to be inserted. 891 * @param s The character sequence to insert into this buffer. 892 * 893 * @return A reference to this buffer. 894 * 895 * @throws NullPointerException If the provided character sequence is 896 * {@code null}. 897 * 898 * @throws IndexOutOfBoundsException If the specified position is negative 899 * or greater than the current length. 900 */ 901 public ByteStringBuffer insert(final int pos, final CharSequence s) 902 throws NullPointerException, IndexOutOfBoundsException 903 { 904 if (s == null) 905 { 906 final NullPointerException e = 907 new NullPointerException(ERR_BS_BUFFER_CHAR_SEQUENCE_NULL.get()); 908 debugCodingError(e); 909 throw e; 910 } 911 912 if ((pos < 0) || (pos > endPos)) 913 { 914 final String message; 915 if (pos < 0) 916 { 917 message = ERR_BS_BUFFER_POS_NEGATIVE.get(pos); 918 } 919 else 920 { 921 message = ERR_BS_BUFFER_POS_TOO_LARGE.get(pos, endPos); 922 } 923 924 final IndexOutOfBoundsException e = 925 new IndexOutOfBoundsException(message); 926 debugCodingError(e); 927 throw e; 928 } 929 else if (pos == endPos) 930 { 931 return append(s); 932 } 933 else 934 { 935 return insert(pos, StaticUtils.getBytes(s.toString())); 936 } 937 } 938 939 940 941 /** 942 * Inserts the provided integer value to this buffer. 943 * 944 * @param pos The position at which the value is to be inserted. 945 * @param i The integer value to be inserted into this buffer. 946 * 947 * @return A reference to this buffer. 948 * 949 * @throws IndexOutOfBoundsException If the specified position is negative 950 * or greater than the current length. 951 */ 952 public ByteStringBuffer insert(final int pos, final int i) 953 throws IndexOutOfBoundsException 954 { 955 final int length = getBytes(i); 956 return insert(pos, TEMP_NUMBER_BUFFER.get(), 0, length); 957 } 958 959 960 961 /** 962 * Inserts the provided long value to this buffer. 963 * 964 * @param pos The position at which the value is to be inserted. 965 * @param l The long value to be inserted into this buffer. 966 * 967 * @return A reference to this buffer. 968 * 969 * @throws IndexOutOfBoundsException If the specified position is negative 970 * or greater than the current length. 971 */ 972 public ByteStringBuffer insert(final int pos, final long l) 973 throws IndexOutOfBoundsException 974 { 975 final int length = getBytes(l); 976 return insert(pos, TEMP_NUMBER_BUFFER.get(), 0, length); 977 } 978 979 980 981 /** 982 * Deletes the specified number of bytes from the beginning of the buffer. 983 * 984 * @param len The number of bytes to delete. 985 * 986 * @return A reference to this buffer. 987 * 988 * @throws IndexOutOfBoundsException If the specified length is negative, 989 * or if it is greater than the number of 990 * bytes currently contained in this 991 * buffer. 992 */ 993 public ByteStringBuffer delete(final int len) 994 throws IndexOutOfBoundsException 995 { 996 return delete(0, len); 997 } 998 999 1000 1001 /** 1002 * Deletes the indicated number of bytes from the specified location in the 1003 * buffer. 1004 * 1005 * @param off The position in the buffer at which the content to delete 1006 * begins. 1007 * @param len The number of bytes to remove from the buffer. 1008 * 1009 * @return A reference to this buffer. 1010 * 1011 * @throws IndexOutOfBoundsException If the offset or length is negative, or 1012 * if the combination of the offset and 1013 * length is greater than the end of the 1014 * content in the buffer. 1015 */ 1016 public ByteStringBuffer delete(final int off, final int len) 1017 throws IndexOutOfBoundsException 1018 { 1019 if (off < 0) 1020 { 1021 throw new IndexOutOfBoundsException( 1022 ERR_BS_BUFFER_OFFSET_NEGATIVE.get(off)); 1023 } 1024 else if (len < 0) 1025 { 1026 throw new IndexOutOfBoundsException( 1027 ERR_BS_BUFFER_LENGTH_NEGATIVE.get(len)); 1028 } 1029 else if ((off + len) > endPos) 1030 { 1031 throw new IndexOutOfBoundsException( 1032 ERR_BS_BUFFER_OFFSET_PLUS_LENGTH_TOO_LARGE.get(off, len, endPos)); 1033 } 1034 else if (len == 0) 1035 { 1036 return this; 1037 } 1038 else if (off == 0) 1039 { 1040 if (len == endPos) 1041 { 1042 endPos = 0; 1043 return this; 1044 } 1045 else 1046 { 1047 final int newEndPos = endPos - len; 1048 System.arraycopy(array, len, array, 0, newEndPos); 1049 endPos = newEndPos; 1050 return this; 1051 } 1052 } 1053 else 1054 { 1055 if ((off + len) == endPos) 1056 { 1057 endPos = off; 1058 return this; 1059 } 1060 else 1061 { 1062 final int bytesToCopy = endPos - (off+len); 1063 System.arraycopy(array, (off+len), array, off, bytesToCopy); 1064 endPos -= len; 1065 return this; 1066 } 1067 } 1068 } 1069 1070 1071 1072 /** 1073 * Sets the contents of this buffer to include only the provided boolean 1074 * value. 1075 * 1076 * @param b The boolean value to use as the content for this buffer. 1077 * 1078 * @return A reference to this buffer. 1079 */ 1080 public ByteStringBuffer set(final boolean b) 1081 { 1082 if (b) 1083 { 1084 return set(TRUE_VALUE_BYTES, 0, 4); 1085 } 1086 else 1087 { 1088 return set(FALSE_VALUE_BYTES, 0, 5); 1089 } 1090 } 1091 1092 1093 1094 /** 1095 * Sets the contents of this buffer to include only the provided byte. 1096 * 1097 * @param b The byte to use as the content for this buffer. 1098 * 1099 * @return A reference to this buffer. 1100 */ 1101 public ByteStringBuffer set(final byte b) 1102 { 1103 endPos = 0; 1104 return append(b); 1105 } 1106 1107 1108 1109 /** 1110 * Sets the contents of this buffer to the contents of the provided byte 1111 * array. 1112 * 1113 * @param b The byte array containing the content to use for this buffer. 1114 * 1115 * @throws NullPointerException If the provided array is {@code null}. 1116 * 1117 * @return A reference to this buffer. 1118 */ 1119 public ByteStringBuffer set(final byte[] b) 1120 throws NullPointerException 1121 { 1122 if (b == null) 1123 { 1124 final NullPointerException e = 1125 new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get()); 1126 debugCodingError(e); 1127 throw e; 1128 } 1129 1130 endPos = 0; 1131 return append(b, 0, b.length); 1132 } 1133 1134 1135 1136 /** 1137 * Sets the contents of this buffer to the specified portion of the provided 1138 * byte array. 1139 * 1140 * @param b The byte array containing the content to use for this buffer. 1141 * @param off The offset within the array at which to begin copying data. 1142 * @param len The number of bytes to copy. 1143 * 1144 * @return A reference to this buffer. 1145 * 1146 * @throws NullPointerException If the provided array is {@code null}. 1147 * 1148 * @throws IndexOutOfBoundsException If the offset or length are negative, 1149 * if the offset plus the length is beyond 1150 * the end of the provided array. 1151 */ 1152 public ByteStringBuffer set(final byte[] b, final int off, final int len) 1153 throws NullPointerException, IndexOutOfBoundsException 1154 { 1155 if (b == null) 1156 { 1157 final NullPointerException e = 1158 new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get()); 1159 debugCodingError(e); 1160 throw e; 1161 } 1162 1163 if ((off < 0) || (len < 0) || (off+len > b.length)) 1164 { 1165 final String message; 1166 if (off < 0) 1167 { 1168 message = ERR_BS_BUFFER_OFFSET_NEGATIVE.get(off); 1169 } 1170 else if (len < 0) 1171 { 1172 message = ERR_BS_BUFFER_LENGTH_NEGATIVE.get(len); 1173 } 1174 else 1175 { 1176 message = ERR_BS_BUFFER_OFFSET_PLUS_LENGTH_TOO_LARGE.get(off, len, 1177 b.length); 1178 } 1179 1180 final IndexOutOfBoundsException e = 1181 new IndexOutOfBoundsException(message); 1182 debugCodingError(e); 1183 throw e; 1184 } 1185 1186 endPos = 0; 1187 return append(b, off, len); 1188 } 1189 1190 1191 1192 /** 1193 * Sets the contents of this buffer to the contents of the provided byte 1194 * string. 1195 * 1196 * @param b The byte string that should be used as the content for this 1197 * buffer. 1198 * 1199 * @throws NullPointerException If the provided byte string is {@code null}. 1200 * 1201 * @return A reference to this buffer. 1202 */ 1203 public ByteStringBuffer set(final ByteString b) 1204 throws NullPointerException 1205 { 1206 if (b == null) 1207 { 1208 final NullPointerException e = 1209 new NullPointerException(ERR_BS_BUFFER_BYTE_STRING_NULL.get()); 1210 debugCodingError(e); 1211 throw e; 1212 } 1213 1214 endPos = 0; 1215 b.appendValueTo(this); 1216 return this; 1217 } 1218 1219 1220 1221 /** 1222 * Sets the contents of this buffer to the contents of the provided byte 1223 * string buffer. 1224 * 1225 * @param buffer The buffer whose contents should be used as the content for 1226 * this buffer. 1227 * 1228 * @throws NullPointerException If the provided buffer is {@code null}. 1229 * 1230 * @return A reference to this buffer. 1231 */ 1232 public ByteStringBuffer set(final ByteStringBuffer buffer) 1233 throws NullPointerException 1234 { 1235 if (buffer == null) 1236 { 1237 final NullPointerException e = 1238 new NullPointerException(ERR_BS_BUFFER_BUFFER_NULL.get()); 1239 debugCodingError(e); 1240 throw e; 1241 } 1242 1243 endPos = 0; 1244 return append(buffer.array, 0, buffer.endPos); 1245 } 1246 1247 1248 1249 /** 1250 * Sets the contents of this buffer to include only the provided character. 1251 * 1252 * @param c The character use as the content for this buffer. 1253 * 1254 * @return A reference to this buffer. 1255 */ 1256 public ByteStringBuffer set(final char c) 1257 { 1258 endPos = 0; 1259 return append(c); 1260 } 1261 1262 1263 1264 /** 1265 * Sets the contents of this buffer to the contents of the provided character 1266 * array. 1267 * 1268 * @param c The character array containing the content to use for this 1269 * buffer. 1270 * 1271 * @throws NullPointerException If the provided array is {@code null}. 1272 * 1273 * @return A reference to this buffer. 1274 */ 1275 public ByteStringBuffer set(final char[] c) 1276 throws NullPointerException 1277 { 1278 if (c == null) 1279 { 1280 final NullPointerException e = 1281 new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get()); 1282 debugCodingError(e); 1283 throw e; 1284 } 1285 1286 endPos = 0; 1287 return append(c, 0, c.length); 1288 } 1289 1290 1291 1292 /** 1293 * Sets the contents of this buffer to the specified portion of the provided 1294 * character array. 1295 * 1296 * @param c The character array containing the content to use for this 1297 * buffer. 1298 * @param off The offset within the array at which to begin copying data. 1299 * @param len The number of characters to copy. 1300 * 1301 * @return A reference to this buffer. 1302 * 1303 * @throws NullPointerException If the provided array is {@code null}. 1304 * 1305 * @throws IndexOutOfBoundsException If the offset or length are negative, 1306 * if the offset plus the length is beyond 1307 * the end of the provided array. 1308 */ 1309 public ByteStringBuffer set(final char[] c, final int off, final int len) 1310 throws NullPointerException, IndexOutOfBoundsException 1311 { 1312 if (c == null) 1313 { 1314 final NullPointerException e = 1315 new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get()); 1316 debugCodingError(e); 1317 throw e; 1318 } 1319 1320 if ((off < 0) || (len < 0) || (off+len > c.length)) 1321 { 1322 final String message; 1323 if (off < 0) 1324 { 1325 message = ERR_BS_BUFFER_OFFSET_NEGATIVE.get(off); 1326 } 1327 else if (len < 0) 1328 { 1329 message = ERR_BS_BUFFER_LENGTH_NEGATIVE.get(len); 1330 } 1331 else 1332 { 1333 message = ERR_BS_BUFFER_OFFSET_PLUS_LENGTH_TOO_LARGE.get(off, len, 1334 c.length); 1335 } 1336 1337 final IndexOutOfBoundsException e = 1338 new IndexOutOfBoundsException(message); 1339 debugCodingError(e); 1340 throw e; 1341 } 1342 1343 endPos = 0; 1344 return append(c, off, len); 1345 } 1346 1347 1348 1349 /** 1350 * Sets the contents of this buffer to the specified portion of the provided 1351 * character sequence. 1352 * 1353 * @param s The character sequence to use as the content for this buffer. 1354 * 1355 * @throws NullPointerException If the provided character sequence is 1356 * {@code null}. 1357 * 1358 * @return A reference to this buffer. 1359 */ 1360 public ByteStringBuffer set(final CharSequence s) 1361 throws NullPointerException 1362 { 1363 if (s == null) 1364 { 1365 final NullPointerException e = 1366 new NullPointerException(ERR_BS_BUFFER_CHAR_SEQUENCE_NULL.get()); 1367 debugCodingError(e); 1368 throw e; 1369 } 1370 1371 endPos = 0; 1372 return append(s); 1373 } 1374 1375 1376 1377 /** 1378 * Sets the contents of this buffer to include only the provided integer 1379 * value. 1380 * 1381 * @param i The integer value to use as the content for this buffer. 1382 * 1383 * @return A reference to this buffer. 1384 */ 1385 public ByteStringBuffer set(final int i) 1386 { 1387 final int length = getBytes(i); 1388 return set(TEMP_NUMBER_BUFFER.get(), 0, length); 1389 } 1390 1391 1392 1393 /** 1394 * Sets the contents of this buffer to include only the provided long value. 1395 * 1396 * @param l The long value to use as the content for this buffer. 1397 * 1398 * @return A reference to this buffer. 1399 */ 1400 public ByteStringBuffer set(final long l) 1401 { 1402 final int length = getBytes(l); 1403 return set(TEMP_NUMBER_BUFFER.get(), 0, length); 1404 } 1405 1406 1407 1408 /** 1409 * Clears the contents of this buffer. 1410 * 1411 * @return A reference to this buffer. 1412 */ 1413 public ByteStringBuffer clear() 1414 { 1415 endPos = 0; 1416 return this; 1417 } 1418 1419 1420 1421 /** 1422 * Clears the contents of this buffer. 1423 * 1424 * @param zero Indicates whether to overwrite the content of the backing 1425 * array with all zeros in order to wipe out any sensitive data 1426 * it may contain. 1427 * 1428 * @return A reference to this buffer. 1429 */ 1430 public ByteStringBuffer clear(final boolean zero) 1431 { 1432 endPos = 0; 1433 1434 if (zero) 1435 { 1436 Arrays.fill(array, (byte) 0x00); 1437 } 1438 1439 return this; 1440 } 1441 1442 1443 1444 /** 1445 * Retrieves the current backing array for this buffer. The data will begin 1446 * at position 0 and will contain {@link ByteStringBuffer#length} bytes. 1447 * 1448 * @return The current backing array for this buffer. 1449 */ 1450 public byte[] getBackingArray() 1451 { 1452 return array; 1453 } 1454 1455 1456 1457 /** 1458 * Indicates whether this buffer is currently empty. 1459 * 1460 * @return {@code true} if this buffer is currently empty, or {@code false} 1461 * if not. 1462 */ 1463 public boolean isEmpty() 1464 { 1465 return (endPos == 0); 1466 } 1467 1468 1469 1470 /** 1471 * Retrieves the number of bytes contained in this buffer. 1472 * 1473 * @return The number of bytes contained in this buffer. 1474 */ 1475 public int length() 1476 { 1477 return endPos; 1478 } 1479 1480 1481 1482 /** 1483 * Sets the length of this buffer to the specified value. If the new length 1484 * is greater than the current length, the value will be padded with zeroes. 1485 * 1486 * @param length The new length to use for the buffer. It must be greater 1487 * than or equal to zero. 1488 * 1489 * @throws IndexOutOfBoundsException If the provided length is negative. 1490 */ 1491 public void setLength(final int length) 1492 throws IndexOutOfBoundsException 1493 { 1494 if (length < 0) 1495 { 1496 final IndexOutOfBoundsException e = new IndexOutOfBoundsException( 1497 ERR_BS_BUFFER_LENGTH_NEGATIVE.get(length)); 1498 debugCodingError(e); 1499 throw e; 1500 } 1501 1502 if (length > endPos) 1503 { 1504 ensureCapacity(length); 1505 Arrays.fill(array, endPos, length, (byte) 0x00); 1506 endPos = length; 1507 } 1508 else 1509 { 1510 endPos = length; 1511 } 1512 } 1513 1514 1515 1516 /** 1517 * Returns the current capacity for this buffer. 1518 * 1519 * @return The current capacity for this buffer. 1520 */ 1521 public int capacity() 1522 { 1523 return capacity; 1524 } 1525 1526 1527 1528 /** 1529 * Ensures that the total capacity of this buffer is at least equal to the 1530 * specified size. 1531 * 1532 * @param minimumCapacity The minimum capacity for this buffer. 1533 */ 1534 public void ensureCapacity(final int minimumCapacity) 1535 { 1536 if (capacity < minimumCapacity) 1537 { 1538 final int newCapacity = Math.max(minimumCapacity, (2 * capacity) + 2); 1539 final byte[] newArray = new byte[newCapacity]; 1540 System.arraycopy(array, 0, newArray, 0, capacity); 1541 array = newArray; 1542 capacity = newCapacity; 1543 } 1544 } 1545 1546 1547 1548 /** 1549 * Sets the capacity equal to the specified value. If the provided capacity 1550 * is less than the current length, then the length will be reduced to the 1551 * new capacity. 1552 * 1553 * @param capacity The new capacity for this buffer. It must be greater 1554 * than or equal to zero. 1555 * 1556 * @throws IndexOutOfBoundsException If the provided capacity is negative. 1557 */ 1558 public void setCapacity(final int capacity) 1559 throws IndexOutOfBoundsException 1560 { 1561 if (capacity < 0) 1562 { 1563 final IndexOutOfBoundsException e = new IndexOutOfBoundsException( 1564 ERR_BS_BUFFER_CAPACITY_NEGATIVE.get(capacity)); 1565 debugCodingError(e); 1566 throw e; 1567 } 1568 1569 if (this.capacity == capacity) 1570 { 1571 return; 1572 } 1573 else if (this.capacity < capacity) 1574 { 1575 final byte[] newArray = new byte[capacity]; 1576 System.arraycopy(array, 0, newArray, 0, this.capacity); 1577 array = newArray; 1578 this.capacity = capacity; 1579 } 1580 else 1581 { 1582 final byte[] newArray = new byte[capacity]; 1583 System.arraycopy(array, 0, newArray, 0, capacity); 1584 array = newArray; 1585 endPos = Math.min(endPos, capacity); 1586 this.capacity = capacity; 1587 } 1588 } 1589 1590 1591 1592 /** 1593 * Trims the backing array to the minimal size required for this buffer. 1594 * 1595 * @return A reference to this buffer. 1596 */ 1597 public ByteStringBuffer trimToSize() 1598 { 1599 if (endPos != capacity) 1600 { 1601 final byte[] newArray = new byte[endPos]; 1602 System.arraycopy(array, 0, newArray, 0, endPos); 1603 array = newArray; 1604 capacity = endPos; 1605 } 1606 1607 return this; 1608 } 1609 1610 1611 1612 /** 1613 * Returns a new byte array with the content from this buffer. 1614 * 1615 * @return A byte array containing the content from this buffer. 1616 */ 1617 public byte[] toByteArray() 1618 { 1619 final byte[] newArray = new byte[endPos]; 1620 System.arraycopy(array, 0, newArray, 0, endPos); 1621 return newArray; 1622 } 1623 1624 1625 1626 /** 1627 * Returns a new byte string with the content from this buffer. 1628 * 1629 * @return A byte string with the content from this buffer. 1630 */ 1631 public ByteString toByteString() 1632 { 1633 return new ASN1OctetString(toByteArray()); 1634 } 1635 1636 1637 1638 /** 1639 * Creates an input stream that may be used to read content from this buffer. 1640 * This buffer should not be altered while the input stream is being used. 1641 * 1642 * @return An input stream that may be used to read content from this buffer. 1643 */ 1644 public InputStream asInputStream() 1645 { 1646 return new ByteArrayInputStream(array, 0, endPos); 1647 } 1648 1649 1650 1651 /** 1652 * Writes the contents of this byte string buffer to the provided output 1653 * stream. 1654 * 1655 * @param outputStream The output stream to which the data should be 1656 * written. 1657 * 1658 * @throws IOException If a problem occurs while writing to the provided 1659 * output stream. 1660 */ 1661 public void write(final OutputStream outputStream) 1662 throws IOException 1663 { 1664 outputStream.write(array, 0, endPos); 1665 } 1666 1667 1668 1669 /** 1670 * Adds the bytes comprising the string representation of the provided long 1671 * value to the temporary number buffer. 1672 * 1673 * @param l The long value to be appended. 1674 * 1675 * @return The number of bytes in the string representation of the value. 1676 */ 1677 private static int getBytes(final long l) 1678 { 1679 // NOTE: This method is probably not as efficient as it could be, but it is 1680 // more important to avoid the need for memory allocation. 1681 byte[] b = TEMP_NUMBER_BUFFER.get(); 1682 if (b == null) 1683 { 1684 b = new byte[20]; 1685 TEMP_NUMBER_BUFFER.set(b); 1686 } 1687 1688 if (l == Long.MIN_VALUE) 1689 { 1690 b[0] = '-'; 1691 b[1] = '9'; 1692 b[2] = '2'; 1693 b[3] = '2'; 1694 b[4] = '3'; 1695 b[5] = '3'; 1696 b[6] = '7'; 1697 b[7] = '2'; 1698 b[8] = '0'; 1699 b[9] = '3'; 1700 b[10] = '6'; 1701 b[11] = '8'; 1702 b[12] = '5'; 1703 b[13] = '4'; 1704 b[14] = '7'; 1705 b[15] = '7'; 1706 b[16] = '5'; 1707 b[17] = '8'; 1708 b[18] = '0'; 1709 b[19] = '8'; 1710 return 20; 1711 } 1712 else if (l == 0L) 1713 { 1714 b[0] = '0'; 1715 return 1; 1716 } 1717 1718 int pos = 0; 1719 long v = l; 1720 if (l < 0) 1721 { 1722 b[0] = '-'; 1723 pos = 1; 1724 v = Math.abs(l); 1725 } 1726 1727 long divisor; 1728 if (v <= 9L) 1729 { 1730 divisor = 1L; 1731 } 1732 else if (v <= 99L) 1733 { 1734 divisor = 10L; 1735 } 1736 else if (v <= 999L) 1737 { 1738 divisor = 100L; 1739 } 1740 else if (v <= 9999L) 1741 { 1742 divisor = 1000L; 1743 } 1744 else if (v <= 99999L) 1745 { 1746 divisor = 10000L; 1747 } 1748 else if (v <= 999999L) 1749 { 1750 divisor = 100000L; 1751 } 1752 else if (v <= 9999999L) 1753 { 1754 divisor = 1000000L; 1755 } 1756 else if (v <= 99999999L) 1757 { 1758 divisor = 10000000L; 1759 } 1760 else if (v <= 999999999L) 1761 { 1762 divisor = 100000000L; 1763 } 1764 else if (v <= 9999999999L) 1765 { 1766 divisor = 1000000000L; 1767 } 1768 else if (v <= 99999999999L) 1769 { 1770 divisor = 10000000000L; 1771 } 1772 else if (v <= 999999999999L) 1773 { 1774 divisor = 100000000000L; 1775 } 1776 else if (v <= 9999999999999L) 1777 { 1778 divisor = 1000000000000L; 1779 } 1780 else if (v <= 99999999999999L) 1781 { 1782 divisor = 10000000000000L; 1783 } 1784 else if (v <= 999999999999999L) 1785 { 1786 divisor = 100000000000000L; 1787 } 1788 else if (v <= 9999999999999999L) 1789 { 1790 divisor = 1000000000000000L; 1791 } 1792 else if (v <= 99999999999999999L) 1793 { 1794 divisor = 10000000000000000L; 1795 } 1796 else if (v <= 999999999999999999L) 1797 { 1798 divisor = 100000000000000000L; 1799 } 1800 else 1801 { 1802 divisor = 1000000000000000000L; 1803 } 1804 1805 while (true) 1806 { 1807 final long digit = v / divisor; 1808 switch ((int) digit) 1809 { 1810 case 0: 1811 b[pos++] = '0'; 1812 break; 1813 case 1: 1814 b[pos++] = '1'; 1815 break; 1816 case 2: 1817 b[pos++] = '2'; 1818 break; 1819 case 3: 1820 b[pos++] = '3'; 1821 break; 1822 case 4: 1823 b[pos++] = '4'; 1824 break; 1825 case 5: 1826 b[pos++] = '5'; 1827 break; 1828 case 6: 1829 b[pos++] = '6'; 1830 break; 1831 case 7: 1832 b[pos++] = '7'; 1833 break; 1834 case 8: 1835 b[pos++] = '8'; 1836 break; 1837 case 9: 1838 b[pos++] = '9'; 1839 break; 1840 } 1841 1842 if (divisor == 1L) 1843 { 1844 break; 1845 } 1846 else 1847 { 1848 v -= (divisor * digit); 1849 if (v == 0) 1850 { 1851 while (divisor > 1L) 1852 { 1853 b[pos++] = '0'; 1854 divisor /= 10L; 1855 } 1856 1857 break; 1858 } 1859 1860 divisor /= 10L; 1861 } 1862 } 1863 1864 return pos; 1865 } 1866 1867 1868 1869 /** 1870 * Retrieves a hash code for this byte array. 1871 * 1872 * @return A hash code for this byte array. 1873 */ 1874 @Override() 1875 public int hashCode() 1876 { 1877 int hashCode = 0; 1878 1879 for (int i=0; i < endPos; i++) 1880 { 1881 hashCode += array[i]; 1882 } 1883 1884 return hashCode; 1885 } 1886 1887 1888 1889 /** 1890 * Indicates whether the provided object is a byte string buffer with contents 1891 * that are identical to that of this buffer. 1892 * 1893 * @param o The object for which to make the determination. 1894 * 1895 * @return {@code true} if the provided object is considered equal to this 1896 * buffer, or {@code false} if not. 1897 */ 1898 @Override() 1899 public boolean equals(final Object o) 1900 { 1901 if (o == null) 1902 { 1903 return false; 1904 } 1905 1906 if (o == this) 1907 { 1908 return true; 1909 } 1910 1911 if (! (o instanceof ByteStringBuffer)) 1912 { 1913 return false; 1914 } 1915 1916 final ByteStringBuffer b = (ByteStringBuffer) o; 1917 if (endPos != b.endPos) 1918 { 1919 return false; 1920 } 1921 1922 for (int i=0; i < endPos; i++) 1923 { 1924 if (array[i] != b.array[i]) 1925 { 1926 return false; 1927 } 1928 } 1929 1930 return true; 1931 } 1932 1933 1934 1935 /** 1936 * Creates a duplicate of this byte string buffer. It will have identical 1937 * content but with a different backing array. Changes to this byte string 1938 * buffer will not impact the duplicate, and vice-versa. 1939 * 1940 * @return A duplicate of this byte string buffer. 1941 */ 1942 public ByteStringBuffer duplicate() 1943 { 1944 final ByteStringBuffer newBuffer = new ByteStringBuffer(endPos); 1945 return newBuffer.append(this); 1946 } 1947 1948 1949 1950 /** 1951 * Retrieves a string representation of the contents for this buffer. 1952 * 1953 * @return A string representation of the contents for this buffer. 1954 */ 1955 @Override() 1956 public String toString() 1957 { 1958 return StaticUtils.toUTF8String(array, 0, endPos); 1959 } 1960}