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