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