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-2010 Sun Microsystems, Inc. 025 * Portions copyright 2011-2015 ForgeRock AS 026 */ 027package org.forgerock.opendj.ldap; 028 029import static com.forgerock.opendj.ldap.CoreMessages.*; 030import static com.forgerock.opendj.util.StaticUtils.*; 031 032import java.io.IOException; 033import java.io.OutputStream; 034import java.io.UnsupportedEncodingException; 035import java.nio.ByteBuffer; 036import java.nio.CharBuffer; 037import java.nio.charset.Charset; 038import java.nio.charset.CharsetDecoder; 039import java.nio.charset.CoderResult; 040import java.util.Arrays; 041 042import org.forgerock.i18n.LocalizedIllegalArgumentException; 043 044import com.forgerock.opendj.util.StaticUtils; 045 046/** 047 * An immutable sequence of bytes backed by a byte array. 048 */ 049public final class ByteString implements ByteSequence { 050 051 /** Singleton empty byte string. */ 052 private static final ByteString EMPTY = wrap(new byte[0]); 053 054 /** 055 * Returns an empty byte string. 056 * 057 * @return An empty byte string. 058 */ 059 public static ByteString empty() { 060 return EMPTY; 061 } 062 063 /** 064 * Returns a byte string containing the big-endian encoded bytes of the 065 * provided integer. 066 * 067 * @param i 068 * The integer to encode. 069 * @return The byte string containing the big-endian encoded bytes of the 070 * provided integer. 071 */ 072 public static ByteString valueOf(int i) { 073 final byte[] bytes = new byte[4]; 074 for (int j = 3; j >= 0; j--) { 075 bytes[j] = (byte) (i & 0xFF); 076 i >>>= 8; 077 } 078 return wrap(bytes); 079 } 080 081 /** 082 * Returns a byte string containing the big-endian encoded bytes of the 083 * provided long. 084 * 085 * @param l 086 * The long to encode. 087 * @return The byte string containing the big-endian encoded bytes of the 088 * provided long. 089 */ 090 public static ByteString valueOf(long l) { 091 final byte[] bytes = new byte[8]; 092 for (int i = 7; i >= 0; i--) { 093 bytes[i] = (byte) (l & 0xFF); 094 l >>>= 8; 095 } 096 return wrap(bytes); 097 } 098 099 /** 100 * Returns a byte string representation of the provided object. The object 101 * is converted to a byte string as follows: 102 * <ul> 103 * <li>if the object is an instance of {@code ByteSequence} then this method 104 * is equivalent to calling {@code o.toByteString()} 105 * <li>if the object is a {@code byte[]} then this method is equivalent to 106 * calling {@link #valueOf(byte[])} 107 * <li>if the object is a {@code char[]} then this method is equivalent to 108 * calling {@link #valueOf(char[])} 109 * <li>for all other types of object this method is equivalent to calling 110 * {@link #valueOf(String)} with the {@code toString()} representation of 111 * the provided object. 112 * </ul> 113 * <b>Note:</b> this method treats {@code Long} and {@code Integer} objects 114 * like any other type of {@code Object}. More specifically, the following 115 * invocations are not equivalent: 116 * <ul> 117 * <li>{@code valueOf(0)} is not equivalent to {@code valueOf((Object) 0)} 118 * <li>{@code valueOf(0L)} is not equivalent to {@code valueOf((Object) 0L)} 119 * </ul> 120 * 121 * @param o 122 * The object to use. 123 * @return The byte string containing the provided object. 124 */ 125 public static ByteString valueOf(final Object o) { 126 if (o instanceof ByteSequence) { 127 return ((ByteSequence) o).toByteString(); 128 } else if (o instanceof byte[]) { 129 return valueOf((byte[]) o); 130 } else if (o instanceof char[]) { 131 return valueOf((char[]) o); 132 } else { 133 return valueOf(o.toString()); 134 } 135 } 136 137 /** 138 * Returns a byte string containing the UTF-8 encoded bytes of the provided 139 * char sequence. 140 * 141 * @param s 142 * The char sequence to use. 143 * @return The byte string with the encoded bytes of the provided string. 144 */ 145 public static ByteString valueOf(final CharSequence s) { 146 if (s.length() == 0) { 147 return EMPTY; 148 } 149 return wrap(StaticUtils.getBytes(s)); 150 } 151 152 /** 153 * Returns a byte string containing the Base64 decoded bytes of the provided 154 * string. 155 * 156 * @param s 157 * The string to use. 158 * @return The byte string containing the Base64 decoded bytes of the 159 * provided string. 160 * @throws LocalizedIllegalArgumentException 161 * If the provided string does not contain valid Base64 encoded 162 * content. 163 * @see #toBase64String() 164 */ 165 public static ByteString valueOfBase64(final String s) { 166 if (s.length() == 0) { 167 return EMPTY; 168 } 169 return Base64.decode(s); 170 } 171 172 /** 173 * Returns a byte string containing the bytes of the provided hexadecimal string. 174 * 175 * @param hexString 176 * The hexadecimal string to convert to a byte array. 177 * @return The byte string containing the binary representation of the 178 * provided hex string. 179 * @throws LocalizedIllegalArgumentException 180 * If the provided string contains invalid hexadecimal digits or 181 * does not contain an even number of digits. 182 */ 183 public static ByteString valueOfHex(final String hexString) { 184 if (hexString == null || hexString.length() == 0) { 185 return EMPTY; 186 } 187 188 final int length = hexString.length(); 189 if (length % 2 != 0) { 190 throw new LocalizedIllegalArgumentException(ERR_HEX_DECODE_INVALID_LENGTH.get(hexString)); 191 } 192 final int arrayLength = length / 2; 193 final byte[] bytes = new byte[arrayLength]; 194 for (int i = 0; i < arrayLength; i++) { 195 bytes[i] = hexToByte(hexString, hexString.charAt(i * 2), hexString.charAt(i * 2 + 1)); 196 } 197 return valueOf(bytes); 198 } 199 200 /** 201 * Returns a byte string containing the contents of the provided byte array. 202 * <p> 203 * This method differs from {@link #wrap(byte[])} in that it defensively 204 * copies the provided byte array. 205 * 206 * @param bytes 207 * The byte array to use. 208 * @return A byte string containing a copy of the provided byte array. 209 */ 210 public static ByteString valueOf(final byte[] bytes) { 211 if (bytes.length == 0) { 212 return EMPTY; 213 } 214 return wrap(Arrays.copyOf(bytes, bytes.length)); 215 } 216 217 /** 218 * Returns a byte string containing a subsequence of the contents of the 219 * provided byte array. 220 * <p> 221 * This method differs from {@link #wrap(byte[], int, int)} in that it 222 * defensively copies the provided byte array. 223 * 224 * @param bytes 225 * The byte array to use. 226 * @param offset 227 * The offset of the byte array to be used; must be non-negative 228 * and no larger than {@code bytes.length} . 229 * @param length 230 * The length of the byte array to be used; must be non-negative 231 * and no larger than {@code bytes.length - offset}. 232 * @return A byte string containing a copy of the subsequence of the 233 * provided byte array. 234 */ 235 public static ByteString valueOf(final byte[] bytes, final int offset, final int length) { 236 checkArrayBounds(bytes, offset, length); 237 if (offset == length) { 238 return EMPTY; 239 } 240 return wrap(Arrays.copyOfRange(bytes, offset, offset + length)); 241 } 242 243 /** 244 * Returns a byte string containing the UTF-8 encoded bytes of the provided 245 * char array. 246 * 247 * @param chars 248 * The char array to use. 249 * @return A byte string containing the UTF-8 encoded bytes of the provided 250 * char array. 251 */ 252 public static ByteString valueOf(final char[] chars) { 253 if (chars.length == 0) { 254 return EMPTY; 255 } 256 return wrap(StaticUtils.getBytes(chars)); 257 } 258 259 /** 260 * Returns a byte string that wraps the provided byte array. 261 * <p> 262 * <b>NOTE:</b> this method takes ownership of the provided byte array and, 263 * therefore, the byte array MUST NOT be altered directly after this method 264 * returns. 265 * 266 * @param bytes 267 * The byte array to wrap. 268 * @return The byte string that wraps the given byte array. 269 */ 270 public static ByteString wrap(final byte[] bytes) { 271 return new ByteString(bytes, 0, bytes.length); 272 } 273 274 /** 275 * Returns a byte string that wraps a subsequence of the provided byte 276 * array. 277 * <p> 278 * <b>NOTE:</b> this method takes ownership of the provided byte array and, 279 * therefore, the byte array MUST NOT be altered directly after this method 280 * returns. 281 * 282 * @param bytes 283 * The byte array to wrap. 284 * @param offset 285 * The offset of the byte array to be used; must be non-negative 286 * and no larger than {@code bytes.length} . 287 * @param length 288 * The length of the byte array to be used; must be non-negative 289 * and no larger than {@code bytes.length - offset}. 290 * @return The byte string that wraps the given byte array. 291 * @throws IndexOutOfBoundsException 292 * If {@code offset} is negative or if {@code length} is 293 * negative or if {@code offset + length} is greater than 294 * {@code bytes.length}. 295 */ 296 public static ByteString wrap(final byte[] bytes, final int offset, final int length) { 297 checkArrayBounds(bytes, offset, length); 298 return new ByteString(bytes, offset, length); 299 } 300 301 /** 302 * Checks the array bounds of the provided byte array sub-sequence, throwing 303 * an {@code IndexOutOfBoundsException} if they are illegal. 304 * 305 * @param b 306 * The byte array. 307 * @param offset 308 * The offset of the byte array to be checked; must be 309 * non-negative and no larger than {@code b.length}. 310 * @param length 311 * The length of the byte array to be checked; must be 312 * non-negative and no larger than {@code b.length - offset}. 313 * @throws IndexOutOfBoundsException 314 * If {@code offset} is negative or if {@code length} is 315 * negative or if {@code offset + length} is greater than 316 * {@code b.length}. 317 */ 318 static void checkArrayBounds(final byte[] b, final int offset, final int length) { 319 if (offset < 0 || offset > b.length || length < 0 || offset + length > b.length 320 || offset + length < 0) { 321 throw new IndexOutOfBoundsException(); 322 } 323 } 324 325 /** 326 * Compares two byte array sub-sequences and returns a value that indicates 327 * their relative order. 328 * 329 * @param b1 330 * The byte array containing the first sub-sequence. 331 * @param offset1 332 * The offset of the first byte array sub-sequence. 333 * @param length1 334 * The length of the first byte array sub-sequence. 335 * @param b2 336 * The byte array containing the second sub-sequence. 337 * @param offset2 338 * The offset of the second byte array sub-sequence. 339 * @param length2 340 * The length of the second byte array sub-sequence. 341 * @return A negative integer if first byte array sub-sequence should come 342 * before the second byte array sub-sequence in ascending order, a 343 * positive integer if the first byte array sub-sequence should come 344 * after the byte array sub-sequence in ascending order, or zero if 345 * there is no difference between the two byte array sub-sequences 346 * with regard to ordering. 347 */ 348 static int compareTo(final byte[] b1, final int offset1, final int length1, final byte[] b2, 349 final int offset2, final int length2) { 350 int count = Math.min(length1, length2); 351 int i = offset1; 352 int j = offset2; 353 while (count-- != 0) { 354 final int firstByte = 0xFF & b1[i++]; 355 final int secondByte = 0xFF & b2[j++]; 356 if (firstByte != secondByte) { 357 return firstByte - secondByte; 358 } 359 } 360 return length1 - length2; 361 } 362 363 /** 364 * Indicates whether two byte array sub-sequences are equal. In order for 365 * them to be considered equal, they must contain the same bytes in the same 366 * order. 367 * 368 * @param b1 369 * The byte array containing the first sub-sequence. 370 * @param offset1 371 * The offset of the first byte array sub-sequence. 372 * @param length1 373 * The length of the first byte array sub-sequence. 374 * @param b2 375 * The byte array containing the second sub-sequence. 376 * @param offset2 377 * The offset of the second byte array sub-sequence. 378 * @param length2 379 * The length of the second byte array sub-sequence. 380 * @return {@code true} if the two byte array sub-sequences have the same 381 * content, or {@code false} if not. 382 */ 383 static boolean equals(final byte[] b1, final int offset1, final int length1, final byte[] b2, 384 final int offset2, final int length2) { 385 if (length1 != length2) { 386 return false; 387 } 388 389 int i = offset1; 390 int j = offset2; 391 int count = length1; 392 while (count-- != 0) { 393 if (b1[i++] != b2[j++]) { 394 return false; 395 } 396 } 397 return true; 398 } 399 400 /** 401 * Returns a hash code for the provided byte array sub-sequence. 402 * 403 * @param b 404 * The byte array. 405 * @param offset 406 * The offset of the byte array sub-sequence. 407 * @param length 408 * The length of the byte array sub-sequence. 409 * @return A hash code for the provided byte array sub-sequence. 410 */ 411 static int hashCode(final byte[] b, final int offset, final int length) { 412 int hashCode = 1; 413 int i = offset; 414 int count = length; 415 while (count-- != 0) { 416 hashCode = 31 * hashCode + b[i++]; 417 } 418 return hashCode; 419 } 420 421 /** 422 * Returns the UTF-8 decoded string representation of the provided byte 423 * array sub-sequence. If UTF-8 decoding fails, the platform's default 424 * encoding will be used. 425 * 426 * @param b 427 * The byte array. 428 * @param offset 429 * The offset of the byte array sub-sequence. 430 * @param length 431 * The length of the byte array sub-sequence. 432 * @return The string representation of the byte array sub-sequence. 433 */ 434 static String toString(final byte[] b, final int offset, final int length) { 435 if (length == 0) { 436 return ""; 437 } 438 try { 439 return new String(b, offset, length, "UTF-8"); 440 } catch (final UnsupportedEncodingException e) { 441 // TODO: I18N 442 throw new RuntimeException("Unable to decode bytes as UTF-8 string", e); 443 } 444 } 445 446 private static byte hexToByte(final String value, final char c1, final char c2) { 447 byte b; 448 switch (c1) { 449 case '0': 450 b = 0x00; 451 break; 452 case '1': 453 b = 0x10; 454 break; 455 case '2': 456 b = 0x20; 457 break; 458 case '3': 459 b = 0x30; 460 break; 461 case '4': 462 b = 0x40; 463 break; 464 case '5': 465 b = 0x50; 466 break; 467 case '6': 468 b = 0x60; 469 break; 470 case '7': 471 b = 0x70; 472 break; 473 case '8': 474 b = (byte) 0x80; 475 break; 476 case '9': 477 b = (byte) 0x90; 478 break; 479 case 'A': 480 case 'a': 481 b = (byte) 0xA0; 482 break; 483 case 'B': 484 case 'b': 485 b = (byte) 0xB0; 486 break; 487 case 'C': 488 case 'c': 489 b = (byte) 0xC0; 490 break; 491 case 'D': 492 case 'd': 493 b = (byte) 0xD0; 494 break; 495 case 'E': 496 case 'e': 497 b = (byte) 0xE0; 498 break; 499 case 'F': 500 case 'f': 501 b = (byte) 0xF0; 502 break; 503 default: 504 throw new LocalizedIllegalArgumentException(ERR_HEX_DECODE_INVALID_CHARACTER.get(value, c1)); 505 } 506 507 switch (c2) { 508 case '0': 509 // No action required. 510 break; 511 case '1': 512 b |= 0x01; 513 break; 514 case '2': 515 b |= 0x02; 516 break; 517 case '3': 518 b |= 0x03; 519 break; 520 case '4': 521 b |= 0x04; 522 break; 523 case '5': 524 b |= 0x05; 525 break; 526 case '6': 527 b |= 0x06; 528 break; 529 case '7': 530 b |= 0x07; 531 break; 532 case '8': 533 b |= 0x08; 534 break; 535 case '9': 536 b |= 0x09; 537 break; 538 case 'A': 539 case 'a': 540 b |= 0x0A; 541 break; 542 case 'B': 543 case 'b': 544 b |= 0x0B; 545 break; 546 case 'C': 547 case 'c': 548 b |= 0x0C; 549 break; 550 case 'D': 551 case 'd': 552 b |= 0x0D; 553 break; 554 case 'E': 555 case 'e': 556 b |= 0x0E; 557 break; 558 case 'F': 559 case 'f': 560 b |= 0x0F; 561 break; 562 default: 563 throw new LocalizedIllegalArgumentException(ERR_HEX_DECODE_INVALID_CHARACTER.get(value, c2)); 564 } 565 566 return b; 567 } 568 569 // These are package private so that compression and crypto 570 // functionality may directly access the fields. 571 572 /** The buffer where data is stored. */ 573 final byte[] buffer; 574 575 /** The number of bytes to expose from the buffer. */ 576 final int length; 577 578 /** The start index of the range of bytes to expose through this byte string. */ 579 final int offset; 580 581 /** 582 * Creates a new byte string that wraps a subsequence of the provided byte 583 * array. 584 * <p> 585 * <b>NOTE:</b> this method takes ownership of the provided byte array and, 586 * therefore, the byte array MUST NOT be altered directly after this method 587 * returns. 588 * 589 * @param b 590 * The byte array to wrap. 591 * @param offset 592 * The offset of the byte array to be used; must be non-negative 593 * and no larger than {@code b.length} . 594 * @param length 595 * The length of the byte array to be used; must be non-negative 596 * and no larger than {@code b.length - offset}. 597 */ 598 private ByteString(final byte[] b, final int offset, final int length) { 599 this.buffer = b; 600 this.offset = offset; 601 this.length = length; 602 } 603 604 /** 605 * Returns a {@link ByteSequenceReader} which can be used to incrementally 606 * read and decode data from this byte string. 607 * 608 * @return The {@link ByteSequenceReader} which can be used to incrementally 609 * read and decode data from this byte string. 610 */ 611 @Override 612 public ByteSequenceReader asReader() { 613 return new ByteSequenceReader(this); 614 } 615 616 /** {@inheritDoc} */ 617 @Override 618 public byte byteAt(final int index) { 619 if (index >= length || index < 0) { 620 throw new IndexOutOfBoundsException(); 621 } 622 return buffer[offset + index]; 623 } 624 625 /** {@inheritDoc} */ 626 @Override 627 public int compareTo(final byte[] bytes, final int offset, final int length) { 628 checkArrayBounds(bytes, offset, length); 629 return compareTo(this.buffer, this.offset, this.length, bytes, offset, length); 630 } 631 632 /** {@inheritDoc} */ 633 @Override 634 public int compareTo(final ByteSequence o) { 635 if (this == o) { 636 return 0; 637 } 638 return -o.compareTo(buffer, offset, length); 639 } 640 641 /** {@inheritDoc} */ 642 @Override 643 public byte[] copyTo(final byte[] bytes) { 644 copyTo(bytes, 0); 645 return bytes; 646 } 647 648 /** {@inheritDoc} */ 649 @Override 650 public byte[] copyTo(final byte[] bytes, final int offset) { 651 if (offset < 0) { 652 throw new IndexOutOfBoundsException(); 653 } 654 System.arraycopy(buffer, this.offset, bytes, offset, Math.min(length, bytes.length - offset)); 655 return bytes; 656 } 657 658 /** {@inheritDoc} */ 659 @Override 660 public ByteBuffer copyTo(final ByteBuffer byteBuffer) { 661 byteBuffer.put(buffer, offset, length); 662 byteBuffer.flip(); 663 return byteBuffer; 664 } 665 666 /** {@inheritDoc} */ 667 @Override 668 public ByteStringBuilder copyTo(final ByteStringBuilder builder) { 669 builder.append(buffer, offset, length); 670 return builder; 671 } 672 673 674 /** {@inheritDoc} */ 675 @Override 676 public boolean copyTo(CharBuffer charBuffer, CharsetDecoder decoder) { 677 return copyTo(ByteBuffer.wrap(buffer, offset, length), charBuffer, decoder); 678 } 679 680 /** 681 * Convenience method to copy from a byte buffer to a char buffer using provided decoder to decode 682 * bytes into characters. 683 * <p> 684 * It should not be used directly, prefer instance method of ByteString or ByteStringBuilder instead. 685 */ 686 static boolean copyTo(ByteBuffer inBuffer, CharBuffer outBuffer, CharsetDecoder decoder) { 687 final CoderResult result = decoder.decode(inBuffer, outBuffer, true); 688 decoder.flush(outBuffer); 689 outBuffer.flip(); 690 return !result.isError() && !result.isOverflow(); 691 } 692 693 /** {@inheritDoc} */ 694 @Override 695 public OutputStream copyTo(final OutputStream stream) throws IOException { 696 stream.write(buffer, offset, length); 697 return stream; 698 } 699 700 /** {@inheritDoc} */ 701 @Override 702 public boolean equals(final byte[] bytes, final int offset, final int length) { 703 checkArrayBounds(bytes, offset, length); 704 return equals(this.buffer, this.offset, this.length, bytes, offset, length); 705 } 706 707 /** 708 * Indicates whether the provided object is equal to this byte string. In 709 * order for it to be considered equal, the provided object must be a byte 710 * sequence containing the same bytes in the same order. 711 * 712 * @param o 713 * The object for which to make the determination. 714 * @return {@code true} if the provided object is a byte sequence whose 715 * content is equal to that of this byte string, or {@code false} if 716 * not. 717 */ 718 @Override 719 public boolean equals(final Object o) { 720 if (this == o) { 721 return true; 722 } else if (o instanceof ByteSequence) { 723 final ByteSequence other = (ByteSequence) o; 724 return other.equals(buffer, offset, length); 725 } else { 726 return false; 727 } 728 } 729 730 /** 731 * Returns a hash code for this byte string. It will be the sum of all of 732 * the bytes contained in the byte string. 733 * 734 * @return A hash code for this byte string. 735 */ 736 @Override 737 public int hashCode() { 738 return hashCode(buffer, offset, length); 739 } 740 741 @Override 742 public boolean isEmpty() { 743 return length == 0; 744 } 745 746 /** {@inheritDoc} */ 747 @Override 748 public int length() { 749 return length; 750 } 751 752 /** {@inheritDoc} */ 753 @Override 754 public ByteString subSequence(final int start, final int end) { 755 if (start < 0 || start > end || end > length) { 756 throw new IndexOutOfBoundsException(); 757 } 758 return new ByteString(buffer, offset + start, end - start); 759 } 760 761 /** {@inheritDoc} */ 762 @Override 763 public boolean startsWith(ByteSequence prefix) { 764 if (prefix == null || prefix.length() > length) { 765 return false; 766 } 767 return prefix.equals(buffer, 0, prefix.length()); 768 } 769 770 /** {@inheritDoc} */ 771 @Override 772 public String toBase64String() { 773 return Base64.encode(this); 774 } 775 776 /** 777 * Returns a string representation of the contents of this byte sequence 778 * using hexadecimal characters and a space between each byte. 779 * 780 * @return A string representation of the contents of this byte sequence 781 * using hexadecimal characters. 782 */ 783 public String toHexString() { 784 if (isEmpty()) { 785 return ""; 786 } 787 StringBuilder builder = new StringBuilder((length - 1) * 3 + 2); 788 builder.append(StaticUtils.byteToHex(buffer[offset])); 789 for (int i = 1; i < length; i++) { 790 builder.append(' '); 791 builder.append(StaticUtils.byteToHex(buffer[offset + i])); 792 } 793 return builder.toString(); 794 } 795 796 /** 797 * Returns a string representation of the contents of this byte sequence 798 * using hexadecimal characters and a percent prefix (#) before each char. 799 * 800 * @return A string representation of the contents of this byte sequence 801 * using percent + hexadecimal characters. 802 */ 803 public String toPercentHexString() { 804 if (isEmpty()) { 805 return ""; 806 } 807 StringBuilder builder = new StringBuilder(length * 3); 808 for (int i = 0; i < length; i++) { 809 builder.append('%'); 810 builder.append(StaticUtils.byteToHex(buffer[offset + i])); 811 } 812 return builder.toString(); 813 } 814 815 /** 816 * Returns a string representation of the data in this byte sequence using 817 * the specified indent. 818 * <p> 819 * The data will be formatted with sixteen hex bytes in a row followed by 820 * the ASCII representation, then wrapping to a new line as necessary. The 821 * state of the byte buffer is not changed. 822 * 823 * @param indent 824 * The number of spaces to indent the output. 825 * @return the string representation of this byte string 826 */ 827 public String toHexPlusAsciiString(int indent) { 828 StringBuilder builder = new StringBuilder(); 829 StringBuilder indentBuf = new StringBuilder(indent); 830 for (int i = 0; i < indent; i++) { 831 indentBuf.append(' '); 832 } 833 int pos = 0; 834 while (length - pos >= 16) { 835 StringBuilder asciiBuf = new StringBuilder(17); 836 byte currentByte = buffer[offset + pos]; 837 builder.append(indentBuf); 838 builder.append(byteToHex(currentByte)); 839 asciiBuf.append(byteToASCII(currentByte)); 840 pos++; 841 842 for (int i = 1; i < 16; i++, pos++) { 843 currentByte = buffer[offset + pos]; 844 builder.append(' '); 845 builder.append(byteToHex(currentByte)); 846 asciiBuf.append(byteToASCII(currentByte)); 847 848 if (i == 7) { 849 builder.append(" "); 850 asciiBuf.append(' '); 851 } 852 } 853 854 builder.append(" "); 855 builder.append(asciiBuf); 856 builder.append(EOL); 857 } 858 859 int remaining = length - pos; 860 if (remaining > 0) { 861 StringBuilder asciiBuf = new StringBuilder(remaining + 1); 862 863 byte currentByte = buffer[offset + pos]; 864 builder.append(indentBuf); 865 builder.append(byteToHex(currentByte)); 866 asciiBuf.append(byteToASCII(currentByte)); 867 pos++; 868 869 for (int i = 1; i < 16; i++, pos++) { 870 builder.append(' '); 871 872 if (i < remaining) { 873 currentByte = buffer[offset + pos]; 874 builder.append(byteToHex(currentByte)); 875 asciiBuf.append(byteToASCII(currentByte)); 876 } else { 877 builder.append(" "); 878 } 879 880 if (i == 7) { 881 builder.append(" "); 882 883 if (i < remaining) { 884 asciiBuf.append(' '); 885 } 886 } 887 } 888 889 builder.append(" "); 890 builder.append(asciiBuf); 891 builder.append(EOL); 892 } 893 return builder.toString(); 894 } 895 896 /** {@inheritDoc} */ 897 @Override 898 public byte[] toByteArray() { 899 return copyTo(new byte[length]); 900 } 901 902 /** {@inheritDoc} */ 903 @Override 904 public ByteString toByteString() { 905 return this; 906 } 907 908 /** 909 * Returns the UTF-8 decoded char array representation of this byte 910 * sequence. 911 * 912 * @return The UTF-8 decoded char array representation of this byte 913 * sequence. 914 */ 915 public char[] toCharArray() { 916 Charset utf8 = Charset.forName("UTF-8"); 917 CharBuffer charBuffer = utf8.decode(ByteBuffer.wrap(buffer, offset, length)); 918 char[] chars = new char[charBuffer.remaining()]; 919 charBuffer.get(chars); 920 return chars; 921 } 922 923 /** 924 * Returns the integer value represented by the first four bytes of this 925 * byte string in big-endian order. 926 * 927 * @return The integer value represented by the first four bytes of this 928 * byte string in big-endian order. 929 * @throws IndexOutOfBoundsException 930 * If this byte string has less than four bytes. 931 */ 932 public int toInt() { 933 if (length < 4) { 934 throw new IndexOutOfBoundsException(); 935 } 936 937 int v = 0; 938 for (int i = 0; i < 4; i++) { 939 v <<= 8; 940 v |= buffer[offset + i] & 0xFF; 941 } 942 return v; 943 } 944 945 /** 946 * Returns the long value represented by the first eight bytes of this byte 947 * string in big-endian order. 948 * 949 * @return The long value represented by the first eight bytes of this byte 950 * string in big-endian order. 951 * @throws IndexOutOfBoundsException 952 * If this byte string has less than eight bytes. 953 */ 954 public long toLong() { 955 if (length < 8) { 956 throw new IndexOutOfBoundsException(); 957 } 958 959 long v = 0; 960 for (int i = 0; i < 8; i++) { 961 v <<= 8; 962 v |= buffer[offset + i] & 0xFF; 963 } 964 return v; 965 } 966 967 /** {@inheritDoc} */ 968 @Override 969 public String toString() { 970 return toString(buffer, offset, length); 971 } 972}