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}