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}