001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2009 Sun Microsystems, Inc. 025 * Portions copyright 2011-2015 ForgeRock AS 026 */ 027package org.forgerock.opendj.ldap; 028 029import java.io.DataInput; 030import java.io.EOFException; 031import java.io.IOException; 032import java.io.InputStream; 033import java.io.OutputStream; 034import java.io.UnsupportedEncodingException; 035import java.nio.ByteBuffer; 036import java.nio.CharBuffer; 037import java.nio.channels.WritableByteChannel; 038import java.nio.charset.Charset; 039import java.nio.charset.CharsetDecoder; 040 041import org.forgerock.util.Reject; 042 043import com.forgerock.opendj.util.PackedLong; 044 045/** A mutable sequence of bytes backed by a byte array. */ 046public final class ByteStringBuilder implements ByteSequence { 047 048 /** Maximum size in bytes of a compact encoded value. */ 049 public static final int MAX_COMPACT_SIZE = PackedLong.MAX_COMPACT_SIZE; 050 051 /** Output stream implementation. */ 052 private final class OutputStreamImpl extends OutputStream { 053 @Override 054 public void close() { 055 // Do nothing. 056 } 057 058 @Override 059 public void write(final byte[] bytes) { 060 appendBytes(bytes); 061 } 062 063 @Override 064 public void write(final byte[] bytes, final int i, final int i1) { 065 appendBytes(bytes, i, i1); 066 } 067 068 @Override 069 public void write(final int i) { 070 appendByte(i); 071 } 072 } 073 074 /** 075 * A sub-sequence of the parent byte string builder. The sub-sequence will 076 * be robust against all updates to the byte string builder except for 077 * invocations of the method {@code clear()}. 078 */ 079 private final class SubSequence implements ByteSequence { 080 081 /** The length of the sub-sequence. */ 082 private final int subLength; 083 084 /** The offset of the sub-sequence. */ 085 private final int subOffset; 086 087 /** 088 * Creates a new sub-sequence. 089 * 090 * @param offset 091 * The offset of the sub-sequence. 092 * @param length 093 * The length of the sub-sequence. 094 */ 095 private SubSequence(final int offset, final int length) { 096 this.subOffset = offset; 097 this.subLength = length; 098 } 099 100 @Override 101 public ByteSequenceReader asReader() { 102 return new ByteSequenceReader(this); 103 } 104 105 @Override 106 public byte byteAt(final int index) { 107 if (index >= subLength || index < 0) { 108 throw new IndexOutOfBoundsException(); 109 } 110 111 // Protect against reallocation: use builder's buffer. 112 return buffer[subOffset + index]; 113 } 114 115 @Override 116 public int compareTo(final byte[] b, final int offset, final int length) { 117 ByteString.checkArrayBounds(b, offset, length); 118 119 // Protect against reallocation: use builder's buffer. 120 return ByteString.compareTo(buffer, subOffset, subLength, b, offset, length); 121 } 122 123 @Override 124 public int compareTo(final ByteSequence o) { 125 if (this == o) { 126 return 0; 127 } 128 129 // Protect against reallocation: use builder's buffer. 130 return -o.compareTo(buffer, subOffset, subLength); 131 } 132 133 @Override 134 public byte[] copyTo(final byte[] b) { 135 copyTo(b, 0); 136 return b; 137 } 138 139 @Override 140 public byte[] copyTo(final byte[] b, final int offset) { 141 if (offset < 0) { 142 throw new IndexOutOfBoundsException(); 143 } 144 145 // Protect against reallocation: use builder's buffer. 146 System.arraycopy(buffer, subOffset, b, offset, Math.min(subLength, b.length - offset)); 147 return b; 148 } 149 150 @Override 151 public ByteBuffer copyTo(final ByteBuffer byteBuffer) { 152 byteBuffer.put(buffer, subOffset, subLength); 153 return byteBuffer; 154 } 155 156 @Override 157 public ByteStringBuilder copyTo(final ByteStringBuilder builder) { 158 // Protect against reallocation: use builder's buffer. 159 return builder.appendBytes(buffer, subOffset, subLength); 160 } 161 162 @Override 163 public boolean copyTo(CharBuffer charBuffer, CharsetDecoder decoder) { 164 return ByteString.copyTo(ByteBuffer.wrap(buffer, subOffset, subLength), charBuffer, decoder); 165 } 166 167 @Override 168 public OutputStream copyTo(final OutputStream stream) throws IOException { 169 // Protect against reallocation: use builder's buffer. 170 stream.write(buffer, subOffset, subLength); 171 return stream; 172 } 173 174 @Override 175 public boolean equals(final byte[] b, final int offset, final int length) { 176 ByteString.checkArrayBounds(b, offset, length); 177 178 // Protect against reallocation: use builder's buffer. 179 return ByteString.equals(buffer, subOffset, subLength, b, offset, length); 180 } 181 182 @Override 183 public boolean equals(final Object o) { 184 if (this == o) { 185 return true; 186 } else if (o instanceof ByteSequence) { 187 final ByteSequence other = (ByteSequence) o; 188 189 // Protect against reallocation: use builder's buffer. 190 return other.equals(buffer, subOffset, subLength); 191 } else { 192 return false; 193 } 194 } 195 196 @Override 197 public int hashCode() { 198 // Protect against reallocation: use builder's buffer. 199 return ByteString.hashCode(buffer, subOffset, subLength); 200 } 201 202 @Override 203 public boolean isEmpty() { 204 return length == 0; 205 } 206 207 @Override 208 public int length() { 209 return subLength; 210 } 211 212 @Override 213 public ByteSequence subSequence(final int start, final int end) { 214 if (start < 0 || start > end || end > subLength) { 215 throw new IndexOutOfBoundsException(); 216 } 217 218 return new SubSequence(subOffset + start, end - start); 219 } 220 221 @Override 222 public boolean startsWith(ByteSequence prefix) { 223 if (prefix == null || prefix.length() > length) { 224 return false; 225 } 226 return prefix.equals(buffer, 0, prefix.length()); 227 } 228 229 @Override 230 public String toBase64String() { 231 return Base64.encode(this); 232 } 233 234 @Override 235 public byte[] toByteArray() { 236 return copyTo(new byte[subLength]); 237 } 238 239 @Override 240 public ByteString toByteString() { 241 // Protect against reallocation: use builder's buffer. 242 final byte[] b = new byte[subLength]; 243 System.arraycopy(buffer, subOffset, b, 0, subLength); 244 return ByteString.wrap(b); 245 } 246 247 @Override 248 public String toString() { 249 // Protect against reallocation: use builder's buffer. 250 return ByteString.toString(buffer, subOffset, subLength); 251 } 252 } 253 254 // These are package private so that compression and crypto 255 // functionality may directly access the fields. 256 257 /** The buffer where data is stored. */ 258 byte[] buffer; 259 260 /** The number of bytes to expose from the buffer. */ 261 int length; 262 263 /** 264 * The lazily allocated output stream view of this builder. Synchronization 265 * is not necessary because the stream is stateless and race conditions can 266 * be tolerated. 267 */ 268 private OutputStreamImpl os; 269 270 /** Creates a new byte string builder with an initial capacity of 32 bytes. */ 271 public ByteStringBuilder() { 272 // Initially create a 32 byte buffer. 273 this(32); 274 } 275 276 /** 277 * Creates a new byte string builder with the specified initial capacity. 278 * 279 * @param capacity 280 * The initial capacity. 281 * @throws IllegalArgumentException 282 * If the {@code capacity} is negative. 283 */ 284 public ByteStringBuilder(final int capacity) { 285 Reject.ifFalse(capacity >= 0, "capacity must be >= 0"); 286 this.buffer = new byte[capacity]; 287 this.length = 0; 288 } 289 290 /** 291 * Creates a new byte string builder with the content of the provided 292 * ByteSequence. Its capacity is set to the length of the provided 293 * ByteSequence. 294 * 295 * @param bs 296 * The ByteSequence to copy 297 */ 298 public ByteStringBuilder(final ByteSequence bs) { 299 this(bs.length()); 300 bs.copyTo(this); 301 } 302 303 /** 304 * Appends the provided byte to this byte string builder. 305 * <p> 306 * Note: this method accepts an {@code int} for ease of reading and writing. 307 * <p> 308 * This method only keeps the lowest 8-bits of the provided {@code int}. 309 * Higher bits will be truncated. This method performs the equivalent of: 310 * 311 * <pre> 312 * int i = ...; 313 * int i8bits = i & 0xFF; 314 * // only use "i8bits" 315 * </pre> 316 * OR 317 * <pre> 318 * int i = ...; 319 * byte b = (byte) i; 320 * // only use "b" 321 * </pre> 322 * 323 * @param b 324 * The byte to be appended to this byte string builder. 325 * @return This byte string builder. 326 */ 327 public ByteStringBuilder appendByte(final int b) { 328 ensureAdditionalCapacity(1); 329 buffer[length++] = (byte) b; 330 return this; 331 } 332 333 /** 334 * Appends the provided byte array to this byte string builder. 335 * <p> 336 * An invocation of the form: 337 * 338 * <pre> 339 * src.append(bytes) 340 * </pre> 341 * 342 * Behaves in exactly the same way as the invocation: 343 * 344 * <pre> 345 * src.append(bytes, 0, bytes.length); 346 * </pre> 347 * 348 * @param bytes 349 * The byte array to be appended to this byte string builder. 350 * @return This byte string builder. 351 */ 352 public ByteStringBuilder appendBytes(final byte[] bytes) { 353 return appendBytes(bytes, 0, bytes.length); 354 } 355 356 /** 357 * Appends the provided byte array to this byte string builder. 358 * 359 * @param bytes 360 * The byte array to be appended to this byte string builder. 361 * @param offset 362 * The offset of the byte array to be used; must be non-negative 363 * and no larger than {@code bytes.length} . 364 * @param length 365 * The length of the byte array to be used; must be non-negative 366 * and no larger than {@code bytes.length - offset}. 367 * @return This byte string builder. 368 * @throws IndexOutOfBoundsException 369 * If {@code offset} is negative or if {@code length} is 370 * negative or if {@code offset + length} is greater than 371 * {@code bytes.length}. 372 */ 373 public ByteStringBuilder appendBytes(final byte[] bytes, final int offset, final int length) { 374 ByteString.checkArrayBounds(bytes, offset, length); 375 376 if (length != 0) { 377 ensureAdditionalCapacity(length); 378 System.arraycopy(bytes, offset, buffer, this.length, length); 379 this.length += length; 380 } 381 382 return this; 383 } 384 385 /** 386 * Appends the provided {@code ByteBuffer} to this byte string builder. 387 * 388 * @param buffer 389 * The byte buffer to be appended to this byte string builder. 390 * @param length 391 * The number of bytes to be appended from {@code buffer}. 392 * @return This byte string builder. 393 * @throws IndexOutOfBoundsException 394 * If {@code length} is less than zero or greater than 395 * {@code buffer.remaining()}. 396 */ 397 public ByteStringBuilder appendBytes(final ByteBuffer buffer, final int length) { 398 if (length < 0 || length > buffer.remaining()) { 399 throw new IndexOutOfBoundsException(); 400 } 401 402 if (length != 0) { 403 ensureAdditionalCapacity(length); 404 buffer.get(this.buffer, this.length, length); 405 this.length += length; 406 } 407 408 return this; 409 } 410 411 /** 412 * Appends the provided {@link ByteSequence} to this byte string builder. 413 * 414 * @param bytes 415 * The byte sequence to be appended to this byte string builder. 416 * @return This byte string builder. 417 */ 418 public ByteStringBuilder appendBytes(final ByteSequence bytes) { 419 return bytes.copyTo(this); 420 } 421 422 /** 423 * Appends the provided {@link ByteSequenceReader} to this byte string builder. 424 * 425 * @param reader 426 * The byte sequence reader to be appended to this byte string 427 * builder. 428 * @param length 429 * The number of bytes to be appended from {@code reader}. 430 * @return This byte string builder. 431 * @throws IndexOutOfBoundsException 432 * If {@code length} is less than zero or greater than 433 * {@code reader.remaining()}. 434 */ 435 public ByteStringBuilder appendBytes(final ByteSequenceReader reader, final int length) { 436 if (length < 0 || length > reader.remaining()) { 437 throw new IndexOutOfBoundsException(); 438 } 439 440 if (length != 0) { 441 ensureAdditionalCapacity(length); 442 reader.readBytes(buffer, this.length, length); 443 this.length += length; 444 } 445 446 return this; 447 } 448 449 /** 450 * Appends the UTF-8 encoded bytes of the provided char array to this byte 451 * string builder. 452 * 453 * @param chars 454 * The char array whose UTF-8 encoding is to be appended to this 455 * byte string builder. 456 * @return This byte string builder. 457 */ 458 public ByteStringBuilder appendUtf8(final char[] chars) { 459 if (chars == null) { 460 return this; 461 } 462 463 // Assume that each char is 1 byte 464 final int len = chars.length; 465 ensureAdditionalCapacity(len); 466 467 for (int i = 0; i < len; i++) { 468 final char c = chars[i]; 469 final byte b = (byte) (c & 0x0000007F); 470 471 if (c == b) { 472 buffer[this.length + i] = b; 473 } else { 474 // There is a multi-byte char. Defer to JDK. 475 final Charset utf8 = Charset.forName("UTF-8"); 476 final ByteBuffer byteBuffer = utf8.encode(CharBuffer.wrap(chars)); 477 final int remaining = byteBuffer.remaining(); 478 ensureAdditionalCapacity(remaining - len); 479 byteBuffer.get(buffer, this.length, remaining); 480 this.length += remaining; 481 return this; 482 } 483 } 484 485 // The 1 byte char assumption was correct 486 this.length += len; 487 return this; 488 } 489 490 /** 491 * Appends the provided {@code DataInput} to this byte string 492 * builder. 493 * 494 * @param stream 495 * The data input stream to be appended to this byte string 496 * builder. 497 * @param length 498 * The maximum number of bytes to be appended from {@code 499 * input}. 500 * @throws IndexOutOfBoundsException 501 * If {@code length} is less than zero. 502 * @throws EOFException 503 * If this stream reaches the end before reading all the bytes. 504 * @throws IOException 505 * If an I/O error occurs. 506 */ 507 public void appendBytes(DataInput stream, int length) throws EOFException, IOException { 508 if (length < 0) { 509 throw new IndexOutOfBoundsException(); 510 } 511 512 ensureAdditionalCapacity(length); 513 stream.readFully(buffer, this.length, length); 514 this.length += length; 515 } 516 517 /** 518 * Appends the provided {@code InputStream} to this byte string builder. 519 * 520 * @param stream 521 * The input stream to be appended to this byte string builder. 522 * @param length 523 * The maximum number of bytes to be appended from {@code buffer} 524 * . 525 * @return The number of bytes read from the input stream, or {@code -1} if 526 * the end of the input stream has been reached. 527 * @throws IndexOutOfBoundsException 528 * If {@code length} is less than zero. 529 * @throws IOException 530 * If an I/O error occurs. 531 */ 532 public int appendBytes(final InputStream stream, final int length) throws IOException { 533 if (length < 0) { 534 throw new IndexOutOfBoundsException(); 535 } 536 537 ensureAdditionalCapacity(length); 538 final int bytesRead = stream.read(buffer, this.length, length); 539 if (bytesRead > 0) { 540 this.length += bytesRead; 541 } 542 543 return bytesRead; 544 } 545 546 /** 547 * Appends the big-endian encoded bytes of the provided integer to this byte 548 * string builder. 549 * 550 * @param i 551 * The integer whose big-endian encoding is to be appended to 552 * this byte string builder. 553 * @return This byte string builder. 554 */ 555 public ByteStringBuilder appendInt(int i) { 556 ensureAdditionalCapacity(4); 557 for (int j = length + 3; j >= length; j--) { 558 buffer[j] = (byte) i; 559 i >>>= 8; 560 } 561 length += 4; 562 return this; 563 } 564 565 /** 566 * Appends the big-endian encoded bytes of the provided long to this byte 567 * string builder. 568 * 569 * @param l 570 * The long whose big-endian encoding is to be appended to this 571 * byte string builder. 572 * @return This byte string builder. 573 */ 574 public ByteStringBuilder appendLong(long l) { 575 ensureAdditionalCapacity(8); 576 for (int i = length + 7; i >= length; i--) { 577 buffer[i] = (byte) l; 578 l >>>= 8; 579 } 580 length += 8; 581 return this; 582 } 583 584 /** 585 * Appends the compact encoded bytes of the provided unsigned long to this byte 586 * string builder. This method allows to encode unsigned long up to 56 bits using 587 * fewer bytes (from 1 to 8) than append(long). The encoding has the important 588 * property that it preserves ordering, so it can be used for keys. 589 * 590 * @param value 591 * The long whose compact encoding is to be appended to this 592 * byte string builder. 593 * @return This byte string builder. 594 */ 595 public ByteStringBuilder appendCompactUnsigned(long value) { 596 Reject.ifFalse(value >= 0, "value must be >= 0"); 597 try { 598 PackedLong.writeCompactUnsigned(asOutputStream(), value); 599 } catch (IOException e) { 600 throw new IllegalStateException(e); 601 } 602 return this; 603 } 604 605 /** 606 * Appends the byte string representation of the provided object to this 607 * byte string builder. The object is converted to a byte string as follows: 608 * <ul> 609 * <li>if the object is an instance of {@code ByteSequence} then this method 610 * is equivalent to calling {@link #appendBytes(ByteSequence)} 611 * <li>if the object is a {@code byte[]} then this method is equivalent to 612 * calling {@link #appendBytes(byte[])} 613 * <li>if the object is a {@code char[]} then this method is equivalent to 614 * calling {@link #appendUtf8(char[])} 615 * <li>for all other types of object this method is equivalent to calling 616 * {@link #appendUtf8(String)} with the {@code toString()} representation of the 617 * provided object. 618 * </ul> 619 * <b>Note:</b> this method treats {@code Long} and {@code Integer} objects 620 * like any other type of {@code Object}. More specifically, the following 621 * invocations are not equivalent: 622 * <ul> 623 * <li>{@code append(0)} is not equivalent to {@code append((Object) 0)} 624 * <li>{@code append(0L)} is not equivalent to {@code append((Object) 0L)} 625 * </ul> 626 * 627 * @param o 628 * The object to be appended to this byte string builder. 629 * @return This byte string builder. 630 */ 631 public ByteStringBuilder appendObject(final Object o) { 632 if (o == null) { 633 return this; 634 } else if (o instanceof ByteSequence) { 635 return appendBytes((ByteSequence) o); 636 } else if (o instanceof byte[]) { 637 return appendBytes((byte[]) o); 638 } else if (o instanceof char[]) { 639 return appendUtf8((char[]) o); 640 } else { 641 return appendUtf8(o.toString()); 642 } 643 } 644 645 /** 646 * Appends the big-endian encoded bytes of the provided short to this byte 647 * string builder. 648 * <p> 649 * Note: this method accepts an {@code int} for ease of reading and writing. 650 * <p> 651 * This method only keeps the lowest 16-bits of the provided {@code int}. 652 * Higher bits will be truncated. This method performs the equivalent of: 653 * 654 * <pre> 655 * int i = ...; 656 * int i16bits = i & 0xFFFF; 657 * // only use "i16bits" 658 * </pre> 659 * OR 660 * <pre> 661 * int i = ...; 662 * short s = (short) i; 663 * // only use "s" 664 * </pre> 665 * 666 * @param i 667 * The short whose big-endian encoding is to be appended to this 668 * byte string builder. 669 * @return This byte string builder. 670 */ 671 public ByteStringBuilder appendShort(int i) { 672 ensureAdditionalCapacity(2); 673 for (int j = length + 1; j >= length; j--) { 674 buffer[j] = (byte) i; 675 i >>>= 8; 676 } 677 length += 2; 678 return this; 679 } 680 681 /** 682 * Appends the UTF-8 encoded bytes of the provided string to this byte 683 * string builder. 684 * 685 * @param s 686 * The string whose UTF-8 encoding is to be appended to this byte 687 * string builder. 688 * @return This byte string builder. 689 */ 690 public ByteStringBuilder appendUtf8(final String s) { 691 if (s == null) { 692 return this; 693 } 694 695 // Assume that each char is 1 byte 696 final int len = s.length(); 697 ensureAdditionalCapacity(len); 698 699 for (int i = 0; i < len; i++) { 700 final char c = s.charAt(i); 701 final byte b = (byte) (c & 0x0000007F); 702 703 if (c == b) { 704 buffer[this.length + i] = b; 705 } else { 706 // There is a multi-byte char. Defer to JDK 707 try { 708 return appendBytes(s.getBytes("UTF-8")); 709 } catch (final UnsupportedEncodingException e) { 710 // TODO: I18N 711 throw new RuntimeException("Unable to encode String '" + s + "' to UTF-8 bytes", e); 712 } 713 } 714 } 715 716 // The 1 byte char assumption was correct 717 this.length += len; 718 return this; 719 } 720 721 /** 722 * Appends the ASN.1 BER length encoding representation of the provided 723 * integer to this byte string builder. 724 * 725 * @param length 726 * The value to encode using the BER length encoding rules. 727 * @return This byte string builder. 728 */ 729 public ByteStringBuilder appendBERLength(final int length) { 730 if ((length & 0x0000007F) == length) { 731 ensureAdditionalCapacity(1); 732 733 buffer[this.length++] = (byte) length; 734 } else if ((length & 0x000000FF) == length) { 735 ensureAdditionalCapacity(2); 736 737 buffer[this.length++] = (byte) 0x81; 738 buffer[this.length++] = (byte) length; 739 } else if ((length & 0x0000FFFF) == length) { 740 ensureAdditionalCapacity(3); 741 742 buffer[this.length++] = (byte) 0x82; 743 buffer[this.length++] = (byte) (length >> 8); 744 buffer[this.length++] = (byte) length; 745 } else if ((length & 0x00FFFFFF) == length) { 746 ensureAdditionalCapacity(4); 747 748 buffer[this.length++] = (byte) 0x83; 749 buffer[this.length++] = (byte) (length >> 16); 750 buffer[this.length++] = (byte) (length >> 8); 751 buffer[this.length++] = (byte) length; 752 } else { 753 ensureAdditionalCapacity(5); 754 755 buffer[this.length++] = (byte) 0x84; 756 buffer[this.length++] = (byte) (length >> 24); 757 buffer[this.length++] = (byte) (length >> 16); 758 buffer[this.length++] = (byte) (length >> 8); 759 buffer[this.length++] = (byte) length; 760 } 761 return this; 762 } 763 764 /** 765 * Returns an {@link OutputStream} whose write operations append data to 766 * this byte string builder. The returned output stream will never throw an 767 * {@link IOException} and its {@link OutputStream#close() close} method 768 * does not do anything. 769 * 770 * @return An {@link OutputStream} whose write operations append data to 771 * this byte string builder. 772 */ 773 public OutputStream asOutputStream() { 774 if (os == null) { 775 os = new OutputStreamImpl(); 776 } 777 return os; 778 } 779 780 /** 781 * Returns a {@link ByteSequenceReader} which can be used to incrementally 782 * read and decode data from this byte string builder. 783 * <p> 784 * <b>NOTE:</b> all concurrent updates to this byte string builder are 785 * supported with the exception of {@link #clear()}. Any invocations of 786 * {@link #clear()} must be accompanied by a subsequent call to 787 * {@code ByteSequenceReader.rewind()}. 788 * 789 * @return The {@link ByteSequenceReader} which can be used to incrementally 790 * read and decode data from this byte string builder. 791 * @see #clear() 792 */ 793 @Override 794 public ByteSequenceReader asReader() { 795 return new ByteSequenceReader(this); 796 } 797 798 @Override 799 public byte byteAt(final int index) { 800 if (index >= length || index < 0) { 801 throw new IndexOutOfBoundsException(); 802 } 803 return buffer[index]; 804 } 805 806 /** 807 * Returns the current capacity of this byte string builder. The capacity 808 * may increase as more data is appended. 809 * 810 * @return The current capacity of this byte string builder. 811 */ 812 public int capacity() { 813 return buffer.length; 814 } 815 816 /** 817 * Sets the length of this byte string builder to zero. 818 * <p> 819 * <b>NOTE:</b> if this method is called, then 820 * {@code ByteSequenceReader.rewind()} must also be called on any associated 821 * byte sequence readers in order for them to remain valid. 822 * 823 * @return This byte string builder. 824 * @see #asReader() 825 */ 826 public ByteStringBuilder clear() { 827 length = 0; 828 return this; 829 } 830 831 /** 832 * Sets the length of this byte string builder to zero, and resets the 833 * capacity to the specified size if above provided threshold. 834 * <p> 835 * <b>NOTE:</b> if this method is called, then 836 * {@code ByteSequenceReader.rewind()} must also be called on any associated 837 * byte sequence readers in order for them to remain valid. 838 * 839 * @param thresholdCapacity 840 * The threshold capacity triggering a truncate 841 * @param newCapacity 842 * The new capacity. 843 * @return This byte string builder. 844 * @throws IllegalArgumentException 845 * If the {@code newCapacity} is negative or the {@code newCapacity} 846 * is bigger than the {@code thresholdCapacity}. 847 * @see #asReader() 848 */ 849 public ByteStringBuilder clearAndTruncate(int thresholdCapacity, int newCapacity) { 850 if (newCapacity > thresholdCapacity) { 851 throw new IllegalArgumentException("new capacity '" + newCapacity 852 + "' cannot be bigger than threshold capacity '" + thresholdCapacity + "'"); 853 } 854 if (newCapacity < 0) { 855 throw new IllegalArgumentException("new capacity '" + newCapacity + "' cannot be negative."); 856 } 857 if (buffer.length > thresholdCapacity) { 858 // garbage collect excessively large buffers 859 buffer = new byte[newCapacity]; 860 } 861 length = 0; 862 return this; 863 } 864 865 @Override 866 public int compareTo(final byte[] bytes, final int offset, final int length) { 867 ByteString.checkArrayBounds(bytes, offset, length); 868 return ByteString.compareTo(this.buffer, 0, this.length, bytes, offset, length); 869 } 870 871 @Override 872 public int compareTo(final ByteSequence o) { 873 if (this == o) { 874 return 0; 875 } 876 return -o.compareTo(buffer, 0, length); 877 } 878 879 @Override 880 public byte[] copyTo(final byte[] bytes) { 881 copyTo(bytes, 0); 882 return bytes; 883 } 884 885 @Override 886 public byte[] copyTo(final byte[] bytes, final int offset) { 887 if (offset < 0) { 888 throw new IndexOutOfBoundsException(); 889 } 890 System.arraycopy(buffer, 0, bytes, offset, Math.min(length, bytes.length - offset)); 891 return bytes; 892 } 893 894 @Override 895 public ByteBuffer copyTo(final ByteBuffer byteBuffer) { 896 byteBuffer.put(buffer, 0, length); 897 return byteBuffer; 898 } 899 900 @Override 901 public ByteStringBuilder copyTo(final ByteStringBuilder builder) { 902 builder.appendBytes(buffer, 0, length); 903 return builder; 904 } 905 906 @Override 907 public boolean copyTo(CharBuffer charBuffer, CharsetDecoder decoder) { 908 return ByteString.copyTo(ByteBuffer.wrap(buffer, 0, length), charBuffer, decoder); 909 } 910 911 @Override 912 public OutputStream copyTo(final OutputStream stream) throws IOException { 913 stream.write(buffer, 0, length); 914 return stream; 915 } 916 917 /** 918 * Copies the entire contents of this byte string to the provided 919 * {@code WritableByteChannel}. 920 * 921 * @param channel 922 * The {@code WritableByteChannel} to copy to. 923 * @return The number of bytes written, possibly zero 924 * @throws IOException 925 * If some other I/O error occurs 926 * @see WritableByteChannel#write(java.nio.ByteBuffer) 927 */ 928 public int copyTo(WritableByteChannel channel) throws IOException { 929 return channel.write(ByteBuffer.wrap(buffer, 0, length)); 930 } 931 932 /** 933 * Ensures that the specified number of additional bytes will fit in this 934 * byte string builder and resizes it if necessary. 935 * 936 * @param size 937 * The number of additional bytes. 938 * @return This byte string builder. 939 */ 940 public ByteStringBuilder ensureAdditionalCapacity(final int size) { 941 final int newCount = this.length + size; 942 if (newCount > buffer.length) { 943 final byte[] newbuffer = new byte[Math.max(buffer.length << 1, newCount)]; 944 System.arraycopy(buffer, 0, newbuffer, 0, buffer.length); 945 buffer = newbuffer; 946 } 947 return this; 948 } 949 950 @Override 951 public boolean equals(final byte[] bytes, final int offset, final int length) { 952 ByteString.checkArrayBounds(bytes, offset, length); 953 return ByteString.equals(this.buffer, 0, this.length, bytes, offset, length); 954 } 955 956 /** 957 * Indicates whether the provided object is equal to this byte string 958 * builder. In order for it to be considered equal, the provided object must 959 * be a byte sequence containing the same bytes in the same order. 960 * 961 * @param o 962 * The object for which to make the determination. 963 * @return {@code true} if the provided object is a byte sequence whose 964 * content is equal to that of this byte string builder, or 965 * {@code false} if not. 966 */ 967 @Override 968 public boolean equals(final Object o) { 969 if (this == o) { 970 return true; 971 } else if (o instanceof ByteSequence) { 972 final ByteSequence other = (ByteSequence) o; 973 return other.equals(buffer, 0, length); 974 } else { 975 return false; 976 } 977 } 978 979 /** 980 * Returns the byte array that backs this byte string builder. Modifications 981 * to this byte string builder's content may cause the returned array's 982 * content to be modified, and vice versa. 983 * <p> 984 * Note that the length of the returned array is only guaranteed to be the 985 * same as the length of this byte string builder immediately after a call 986 * to {@link #trimToSize()}. 987 * <p> 988 * In addition, subsequent modifications to this byte string builder may 989 * cause the backing byte array to be reallocated thus decoupling the 990 * returned byte array from this byte string builder. 991 * 992 * @return The byte array that backs this byte string builder. 993 */ 994 public byte[] getBackingArray() { 995 return buffer; 996 } 997 998 /** 999 * Returns a hash code for this byte string builder. It will be the sum of 1000 * all of the bytes contained in the byte string builder. 1001 * <p> 1002 * <b>NOTE:</b> subsequent changes to this byte string builder will 1003 * invalidate the returned hash code. 1004 * 1005 * @return A hash code for this byte string builder. 1006 */ 1007 @Override 1008 public int hashCode() { 1009 return ByteString.hashCode(buffer, 0, length); 1010 } 1011 1012 @Override 1013 public boolean isEmpty() { 1014 return length == 0; 1015 } 1016 1017 @Override 1018 public int length() { 1019 return length; 1020 } 1021 1022 /** 1023 * Sets the byte value at the specified index. 1024 * <p> 1025 * An index ranges from zero to {@code length() - 1}. The first byte value 1026 * of the sequence is at index zero, the next at index one, and so on, as 1027 * for array indexing. 1028 * 1029 * @param index 1030 * The index of the byte to be set. 1031 * @param b 1032 * The byte to set on this byte string builder. 1033 * @throws IndexOutOfBoundsException 1034 * If the index argument is negative or not less than length(). 1035 */ 1036 public void setByte(final int index, final byte b) { 1037 if (index >= length || index < 0) { 1038 throw new IndexOutOfBoundsException(); 1039 } 1040 buffer[index] = b; 1041 } 1042 1043 /** 1044 * Sets the length of this byte string builder. 1045 * <p> 1046 * If the <code>newLength</code> argument is less than the current length, 1047 * the length is changed to the specified length. 1048 * <p> 1049 * If the <code>newLength</code> argument is greater than or equal to the 1050 * current length, then the capacity is increased and sufficient null bytes 1051 * are appended so that length becomes the <code>newLength</code> argument. 1052 * <p> 1053 * The <code>newLength</code> argument must be greater than or equal to 1054 * <code>0</code>. 1055 * 1056 * @param newLength 1057 * The new length. 1058 * @return This byte string builder. 1059 * @throws IndexOutOfBoundsException 1060 * If the <code>newLength</code> argument is negative. 1061 */ 1062 public ByteStringBuilder setLength(final int newLength) { 1063 if (newLength < 0) { 1064 throw new IndexOutOfBoundsException("Negative newLength: " + newLength); 1065 } 1066 1067 if (newLength > length) { 1068 ensureAdditionalCapacity(newLength - length); 1069 1070 // Pad with zeros. 1071 for (int i = length; i < newLength; i++) { 1072 buffer[i] = 0; 1073 } 1074 } 1075 length = newLength; 1076 1077 return this; 1078 } 1079 1080 /** 1081 * Returns a new byte sequence that is a subsequence of this byte sequence. 1082 * <p> 1083 * The subsequence starts with the byte value at the specified {@code start} 1084 * index and ends with the byte value at index {@code end - 1}. The length 1085 * (in bytes) of the returned sequence is {@code end - start}, so if 1086 * {@code start 1087 * == end} then an empty sequence is returned. 1088 * <p> 1089 * <b>NOTE:</b> the returned sub-sequence will be robust against all updates 1090 * to the byte string builder except for invocations of the method 1091 * {@link #clear()}. If a permanent immutable byte sequence is required then 1092 * callers should invoke {@code toByteString()} on the returned byte 1093 * sequence. 1094 * 1095 * @param start 1096 * The start index, inclusive. 1097 * @param end 1098 * The end index, exclusive. 1099 * @return The newly created byte subsequence. 1100 */ 1101 @Override 1102 public ByteSequence subSequence(final int start, final int end) { 1103 if (start < 0 || start > end || end > length) { 1104 throw new IndexOutOfBoundsException(); 1105 } 1106 1107 return new SubSequence(start, end - start); 1108 } 1109 1110 @Override 1111 public boolean startsWith(ByteSequence prefix) { 1112 if (prefix == null || prefix.length() > length) { 1113 return false; 1114 } 1115 return prefix.equals(buffer, 0, prefix.length()); 1116 } 1117 1118 @Override 1119 public String toBase64String() { 1120 return Base64.encode(this); 1121 } 1122 1123 @Override 1124 public byte[] toByteArray() { 1125 return copyTo(new byte[length]); 1126 } 1127 1128 /** 1129 * Returns the {@link ByteString} representation of this byte string 1130 * builder. Subsequent changes to this byte string builder will not modify 1131 * the returned {@link ByteString}. 1132 * 1133 * @return The {@link ByteString} representation of this byte sequence. 1134 */ 1135 @Override 1136 public ByteString toByteString() { 1137 final byte[] b = new byte[length]; 1138 System.arraycopy(buffer, 0, b, 0, length); 1139 return ByteString.wrap(b); 1140 } 1141 1142 @Override 1143 public String toString() { 1144 return ByteString.toString(buffer, 0, length); 1145 } 1146 1147 /** 1148 * Attempts to reduce storage used for this byte string builder. If the 1149 * buffer is larger than necessary to hold its current sequence of bytes, 1150 * then it may be resized to become more space efficient. 1151 * 1152 * @return This byte string builder. 1153 */ 1154 public ByteStringBuilder trimToSize() { 1155 if (buffer.length > length) { 1156 final byte[] newBuffer = new byte[length]; 1157 System.arraycopy(buffer, 0, newBuffer, 0, length); 1158 buffer = newBuffer; 1159 } 1160 return this; 1161 } 1162}