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