001    /*
002     * Copyright 2008-2016 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2008-2016 UnboundID Corp.
007     *
008     * This program is free software; you can redistribute it and/or modify
009     * it under the terms of the GNU General Public License (GPLv2 only)
010     * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011     * as published by the Free Software Foundation.
012     *
013     * This program is distributed in the hope that it will be useful,
014     * but WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016     * GNU General Public License for more details.
017     *
018     * You should have received a copy of the GNU General Public License
019     * along with this program; if not, see <http://www.gnu.org/licenses>.
020     */
021    package com.unboundid.util;
022    
023    
024    
025    import java.io.ByteArrayInputStream;
026    import java.io.InputStream;
027    import java.io.IOException;
028    import java.io.OutputStream;
029    import java.io.Serializable;
030    import java.util.Arrays;
031    
032    import com.unboundid.asn1.ASN1OctetString;
033    
034    import static com.unboundid.util.Debug.*;
035    import static com.unboundid.util.UtilityMessages.*;
036    
037    
038    
039    /**
040     * This class provides a growable byte array to which data can be appended.
041     * Methods in this class are not synchronized.
042     */
043    public final class ByteStringBuffer
044           implements Serializable, Appendable
045    {
046      /**
047       * The default initial capacity for this buffer.
048       */
049      private static final int DEFAULT_INITIAL_CAPACITY = 20;
050    
051    
052    
053      /**
054       * The pre-allocated array that will be used for a boolean value of "false".
055       */
056      private static final byte[] FALSE_VALUE_BYTES = StaticUtils.getBytes("false");
057    
058    
059    
060      /**
061       * The pre-allocated array that will be used for a boolean value of "true".
062       */
063      private static final byte[] TRUE_VALUE_BYTES = StaticUtils.getBytes("true");
064    
065    
066    
067      /**
068       * A thread-local byte array that will be used for holding numeric values
069       * to append to the buffer.
070       */
071      private static final ThreadLocal<byte[]> TEMP_NUMBER_BUFFER =
072           new ThreadLocal<byte[]>();
073    
074    
075    
076      /**
077       * The serial version UID for this serializable class.
078       */
079      private static final long serialVersionUID = 2899392249591230998L;
080    
081    
082    
083      // The backing array for this buffer.
084      private byte[] array;
085    
086      // The length of the backing array.
087      private int capacity;
088    
089      // The position at which to append the next data.
090      private int endPos;
091    
092    
093    
094      /**
095       * Creates a new empty byte string buffer with a default initial capacity.
096       */
097      public ByteStringBuffer()
098      {
099        this(DEFAULT_INITIAL_CAPACITY);
100      }
101    
102    
103    
104      /**
105       * Creates a new byte string buffer with the specified capacity.
106       *
107       * @param  initialCapacity  The initial capacity to use for the buffer.  It
108       *                          must be greater than or equal to zero.
109       */
110      public ByteStringBuffer(final int initialCapacity)
111      {
112        array    = new byte[initialCapacity];
113        capacity = initialCapacity;
114        endPos   = 0;
115      }
116    
117    
118    
119      /**
120       * Appends the provided boolean value to this buffer.
121       *
122       * @param  b  The boolean value to be appended to this buffer.
123       *
124       * @return  A reference to this buffer.
125       */
126      public ByteStringBuffer append(final boolean b)
127      {
128        if (b)
129        {
130          return append(TRUE_VALUE_BYTES, 0, 4);
131        }
132        else
133        {
134          return append(FALSE_VALUE_BYTES, 0, 5);
135        }
136      }
137    
138    
139    
140      /**
141       * Appends the provided byte to this buffer.
142       *
143       * @param  b  The byte to be appended to this buffer.
144       *
145       * @return  A reference to this buffer.
146       */
147      public ByteStringBuffer append(final byte b)
148      {
149        ensureCapacity(endPos + 1);
150        array[endPos++] = b;
151        return this;
152      }
153    
154    
155    
156      /**
157       * Appends the contents of the provided byte array to this buffer.
158       *
159       * @param  b  The array whose contents should be appended to this buffer.  It
160       *            must not be {@code null}.
161       *
162       * @return  A reference to this buffer.
163       *
164       * @throws  NullPointerException  If the provided array is {@code null}.
165       */
166      public ByteStringBuffer append(final byte[] b)
167             throws NullPointerException
168      {
169        if (b == null)
170        {
171          final NullPointerException e =
172               new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get());
173          debugCodingError(e);
174          throw e;
175        }
176    
177        return append(b, 0, b.length);
178      }
179    
180    
181    
182      /**
183       * Appends the specified portion of the provided byte array to this buffer.
184       *
185       * @param  b    The array whose contents should be appended to this buffer.
186       * @param  off  The offset within the array at which to begin copying data.
187       * @param  len  The number of bytes to copy.
188       *
189       * @return  A reference to this buffer.
190       *
191       * @throws  NullPointerException  If the provided array is {@code null}.
192       *
193       * @throws  IndexOutOfBoundsException  If the offset or length are negative,
194       *                                     if the offset plus the length is beyond
195       *                                     the end of the provided array.
196       */
197      public ByteStringBuffer append(final byte[] b, final int off, final int len)
198             throws NullPointerException, IndexOutOfBoundsException
199      {
200        if (b == null)
201        {
202          final NullPointerException e =
203               new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get());
204          debugCodingError(e);
205          throw e;
206        }
207    
208        if ((off < 0) || (len < 0) || (off+len > b.length))
209        {
210          final String message;
211          if (off < 0)
212          {
213            message = ERR_BS_BUFFER_OFFSET_NEGATIVE.get(off);
214          }
215          else if (len < 0)
216          {
217            message = ERR_BS_BUFFER_LENGTH_NEGATIVE.get(len);
218          }
219          else
220          {
221            message = ERR_BS_BUFFER_OFFSET_PLUS_LENGTH_TOO_LARGE.get(off, len,
222                                                                     b.length);
223          }
224    
225          final IndexOutOfBoundsException e =
226               new IndexOutOfBoundsException(message);
227          debugCodingError(e);
228          throw e;
229        }
230    
231        if (len > 0)
232        {
233          ensureCapacity(endPos + len);
234          System.arraycopy(b, off, array, endPos, len);
235          endPos += len;
236        }
237    
238        return this;
239      }
240    
241    
242    
243      /**
244       * Appends the provided byte string to this buffer.
245       *
246       * @param  b  The byte string to be appended to this buffer.
247       *
248       * @return  A reference to this buffer.
249       *
250       * @throws  NullPointerException  If the provided byte string is {@code null}.
251       */
252      public ByteStringBuffer append(final ByteString b)
253             throws NullPointerException
254      {
255        if (b == null)
256        {
257          final NullPointerException e =
258               new NullPointerException(ERR_BS_BUFFER_BYTE_STRING_NULL.get());
259          debugCodingError(e);
260          throw e;
261        }
262    
263        b.appendValueTo(this);
264        return this;
265      }
266    
267    
268    
269      /**
270       * Appends the provided byte string buffer to this buffer.
271       *
272       * @param  buffer  The buffer whose contents should be appended to this
273       *                 buffer.
274       *
275       * @return  A reference to this buffer.
276       *
277       * @throws  NullPointerException  If the provided buffer is {@code null}.
278       */
279      public ByteStringBuffer append(final ByteStringBuffer buffer)
280             throws NullPointerException
281      {
282        if (buffer == null)
283        {
284          final NullPointerException e =
285               new NullPointerException(ERR_BS_BUFFER_BUFFER_NULL.get());
286          debugCodingError(e);
287          throw e;
288        }
289    
290        return append(buffer.array, 0, buffer.endPos);
291      }
292    
293    
294    
295      /**
296       * Appends the provided character to this buffer.
297       *
298       * @param  c  The character to be appended to this buffer.
299       *
300       * @return  A reference to this buffer.
301       */
302      public ByteStringBuffer append(final char c)
303      {
304        final byte b = (byte) (c & 0x7F);
305        if (b == c)
306        {
307          ensureCapacity(endPos + 1);
308          array[endPos++] = b;
309        }
310        else
311        {
312          append(String.valueOf(c));
313        }
314    
315        return this;
316      }
317    
318    
319    
320      /**
321       * Appends the contents of the provided character array to this buffer.
322       *
323       * @param  c  The array whose contents should be appended to this buffer.
324       *
325       * @return  A reference to this buffer.
326       *
327       * @throws  NullPointerException  If the provided array is {@code null}.
328       */
329      public ByteStringBuffer append(final char[] c)
330             throws NullPointerException
331      {
332        if (c == null)
333        {
334          final NullPointerException e =
335               new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get());
336          debugCodingError(e);
337          throw e;
338        }
339    
340        return append(c, 0, c.length);
341      }
342    
343    
344    
345      /**
346       * Appends the specified portion of the provided character array to this
347       * buffer.
348       *
349       * @param  c    The array whose contents should be appended to this buffer.
350       * @param  off  The offset within the array at which to begin copying data.
351       * @param  len  The number of characters to copy.
352       *
353       * @return  A reference to this buffer.
354       *
355       * @throws  NullPointerException  If the provided array is {@code null}.
356       *
357       * @throws  IndexOutOfBoundsException  If the offset or length are negative,
358       *                                     if the offset plus the length is beyond
359       *                                     the end of the provided array.
360       */
361      public ByteStringBuffer append(final char[] c, final int off, final int len)
362             throws NullPointerException, IndexOutOfBoundsException
363      {
364        if (c == null)
365        {
366          final NullPointerException e =
367               new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get());
368          debugCodingError(e);
369          throw e;
370        }
371    
372        if ((off < 0) || (len < 0) || (off+len > c.length))
373        {
374          final String message;
375          if (off < 0)
376          {
377            message = ERR_BS_BUFFER_OFFSET_NEGATIVE.get(off);
378          }
379          else if (len < 0)
380          {
381            message = ERR_BS_BUFFER_LENGTH_NEGATIVE.get(len);
382          }
383          else
384          {
385            message = ERR_BS_BUFFER_OFFSET_PLUS_LENGTH_TOO_LARGE.get(off, len,
386                                                                     c.length);
387          }
388    
389          final IndexOutOfBoundsException e =
390               new IndexOutOfBoundsException(message);
391          debugCodingError(e);
392          throw e;
393        }
394    
395        if (len > 0)
396        {
397          ensureCapacity(endPos + len);
398    
399          int pos = off;
400          for (int i=0; i < len; i++, pos++)
401          {
402            final byte b = (byte) (c[pos] & 0x7F);
403            if (b == c[pos])
404            {
405              array[endPos++] = b;
406            }
407            else
408            {
409              append(String.valueOf(c, pos, (off + len - pos)));
410              break;
411            }
412          }
413        }
414    
415        return this;
416      }
417    
418    
419    
420      /**
421       * Appends the provided character sequence to this buffer.
422       *
423       * @param  s  The character sequence to append to this buffer.
424       *
425       * @return  A reference to this buffer.
426       *
427       * @throws  NullPointerException  If the provided character sequence is
428       *                                {@code null}.
429       */
430      public ByteStringBuffer append(final CharSequence s)
431             throws NullPointerException
432      {
433        return append(s, 0, s.length());
434      }
435    
436    
437    
438      /**
439       * Appends the provided character sequence to this buffer.
440       *
441       * @param  s      The character sequence to append to this buffer.
442       * @param  start  The position in the sequence of the first character in the
443       *                sequence to be appended to this buffer.
444       * @param  end    The position in the sequence immediately after the position
445       *                of the last character to be appended.
446       *
447       * @return  A reference to this buffer.
448       *
449       * @throws  NullPointerException  If the provided character sequence is
450       *                                {@code null}.
451       *
452       * @throws  IndexOutOfBoundsException  If the provided start or end positions
453       *                                     are outside the bounds of the given
454       *                                     character sequence.
455       */
456      public ByteStringBuffer append(final CharSequence s, final int start,
457                                     final int end)
458             throws NullPointerException, IndexOutOfBoundsException
459      {
460        if (s == null)
461        {
462          final NullPointerException e =
463               new NullPointerException(ERR_BS_BUFFER_CHAR_SEQUENCE_NULL.get());
464          debugCodingError(e);
465          throw e;
466        }
467    
468        final int length = end - start;
469        ensureCapacity(endPos + length);
470        for (int i=start; i < end; i++)
471        {
472          final char c = s.charAt(i);
473          final byte b = (byte) (c & 0x7F);
474          if (b == c)
475          {
476            array[endPos++] = b;
477          }
478          else
479          {
480            append(StaticUtils.getBytes(s.subSequence(i, length).toString()));
481            break;
482          }
483        }
484    
485        return this;
486      }
487    
488    
489    
490      /**
491       * Appends the provided integer value to this buffer.
492       *
493       * @param  i  The integer value to be appended to this buffer.
494       *
495       * @return  A reference to this buffer.
496       */
497      public ByteStringBuffer append(final int i)
498      {
499        final int length = getBytes(i);
500        return append(TEMP_NUMBER_BUFFER.get(), 0, length);
501      }
502    
503    
504    
505      /**
506       * Appends the provided long value to this buffer.
507       *
508       * @param  l  The long value to be appended to this buffer.
509       *
510       * @return  A reference to this buffer.
511       */
512      public ByteStringBuffer append(final long l)
513      {
514        final int length = getBytes(l);
515        return append(TEMP_NUMBER_BUFFER.get(), 0, length);
516      }
517    
518    
519    
520      /**
521       * Inserts the provided boolean value to this buffer.
522       *
523       * @param  pos  The position at which the value is to be inserted.
524       * @param  b    The boolean value to be inserted into this buffer.
525       *
526       * @return  A reference to this buffer.
527       *
528       * @throws  IndexOutOfBoundsException  If the specified position is negative
529       *                                     or greater than the current length.
530       */
531      public ByteStringBuffer insert(final int pos, final boolean b)
532             throws  IndexOutOfBoundsException
533      {
534        if (b)
535        {
536          return insert(pos, TRUE_VALUE_BYTES, 0, 4);
537        }
538        else
539        {
540          return insert(pos, FALSE_VALUE_BYTES, 0, 5);
541        }
542      }
543    
544    
545    
546      /**
547       * Inserts the provided byte at the specified position in this buffer.
548       *
549       * @param  pos  The position at which the byte is to be inserted.
550       * @param  b    The byte to be inserted into this buffer.
551       *
552       * @return  A reference to this buffer.
553       *
554       * @throws  IndexOutOfBoundsException  If the specified position is negative
555       *                                     or greater than the current length.
556       */
557      public ByteStringBuffer insert(final int pos, final byte b)
558             throws IndexOutOfBoundsException
559      {
560        if ((pos < 0) || (pos > endPos))
561        {
562          final String message;
563          if (pos < 0)
564          {
565            message = ERR_BS_BUFFER_POS_NEGATIVE.get(pos);
566          }
567          else
568          {
569            message = ERR_BS_BUFFER_POS_TOO_LARGE.get(pos, endPos);
570          }
571    
572          final IndexOutOfBoundsException e =
573               new IndexOutOfBoundsException(message);
574          debugCodingError(e);
575          throw e;
576        }
577        else if (pos == endPos)
578        {
579          return append(b);
580        }
581    
582        ensureCapacity(endPos + 1);
583        System.arraycopy(array, pos, array, pos+1, (endPos-pos));
584        array[pos] = b;
585        endPos++;
586        return this;
587      }
588    
589    
590    
591      /**
592       * Inserts the contents of the provided byte array at the specified position
593       * in this buffer.
594       *
595       * @param  pos  The position at which the data is to be inserted.
596       * @param  b    The array whose contents should be inserted into this buffer.
597       *
598       * @return  A reference to this buffer.
599       *
600       * @throws  NullPointerException  If the provided array is {@code null}.
601       *
602       * @throws  IndexOutOfBoundsException  If the specified position is negative
603       *                                     or greater than the current length.
604       */
605      public ByteStringBuffer insert(final int pos, final byte[] b)
606             throws NullPointerException, IndexOutOfBoundsException
607      {
608        if (b == null)
609        {
610          final NullPointerException e =
611               new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get());
612          debugCodingError(e);
613          throw e;
614        }
615    
616        return insert(pos, b, 0, b.length);
617      }
618    
619    
620    
621      /**
622       * Inserts a portion of the data in the provided array at the specified
623       * position in this buffer.
624       *
625       * Appends the specified portion of the provided byte array to this buffer.
626       *
627       * @param  pos  The position at which the data is to be inserted.
628       * @param  b    The array whose contents should be inserted into this buffer.
629       * @param  off  The offset within the array at which to begin copying data.
630       * @param  len  The number of bytes to copy.
631       *
632       * @return  A reference to this buffer.
633       *
634       * @throws  NullPointerException  If the provided array is {@code null}.
635       *
636       * @throws  IndexOutOfBoundsException  If the specified position is negative
637       *                                     or greater than the current length, if
638       *                                     the offset or length are negative, if
639       *                                     the offset plus the length is beyond
640       *                                     the end of the provided array.
641       */
642      public ByteStringBuffer insert(final int pos, final byte[] b, final int off,
643                                     final int len)
644             throws NullPointerException, IndexOutOfBoundsException
645      {
646        if (b == null)
647        {
648          final NullPointerException e =
649               new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get());
650          debugCodingError(e);
651          throw e;
652        }
653    
654        if ((pos < 0) || (pos > endPos) || (off < 0) || (len < 0) ||
655            (off+len > b.length))
656        {
657          final String message;
658          if (pos < 0)
659          {
660            message = ERR_BS_BUFFER_POS_NEGATIVE.get(pos);
661          }
662          else if (pos > endPos)
663          {
664            message = ERR_BS_BUFFER_POS_TOO_LARGE.get(pos, endPos);
665          }
666          else if (off < 0)
667          {
668            message = ERR_BS_BUFFER_OFFSET_NEGATIVE.get(off);
669          }
670          else if (len < 0)
671          {
672            message = ERR_BS_BUFFER_LENGTH_NEGATIVE.get(len);
673          }
674          else
675          {
676            message = ERR_BS_BUFFER_OFFSET_PLUS_LENGTH_TOO_LARGE.get(off, len,
677                                                                     b.length);
678          }
679    
680          final IndexOutOfBoundsException e =
681               new IndexOutOfBoundsException(message);
682          debugCodingError(e);
683          throw e;
684        }
685        else if (len == 0)
686        {
687          return this;
688        }
689        else if (pos == endPos)
690        {
691          return append(b, off, len);
692        }
693    
694        ensureCapacity(endPos + len);
695        System.arraycopy(array, pos, array, pos+len, (endPos-pos));
696        System.arraycopy(b, off, array, pos, len);
697        endPos += len;
698        return this;
699      }
700    
701    
702    
703      /**
704       * Inserts the provided byte string into this buffer at the specified
705       * position.
706       *
707       * @param  pos  The position at which the data is to be inserted.
708       * @param  b    The byte string to insert into this buffer.
709       *
710       * @return  A reference to this buffer.
711       *
712       * @throws  NullPointerException  If the provided buffer is {@code null}.
713       *
714       * @throws  IndexOutOfBoundsException  If the specified position is negative
715       *                                     or greater than the current length.
716       */
717      public ByteStringBuffer insert(final int pos, final ByteString b)
718             throws NullPointerException, IndexOutOfBoundsException
719      {
720        if (b == null)
721        {
722          final NullPointerException e =
723               new NullPointerException(ERR_BS_BUFFER_BYTE_STRING_NULL.get());
724          debugCodingError(e);
725          throw e;
726        }
727    
728        return insert(pos, b.getValue());
729      }
730    
731    
732    
733      /**
734       * Inserts the provided byte string buffer into this buffer at the specified
735       * position.
736       *
737       * @param  pos     The position at which the data is to be inserted.
738       * @param  buffer  The buffer whose contents should be inserted into this
739       *                 buffer.
740       *
741       * @return  A reference to this buffer.
742       *
743       * @throws  NullPointerException  If the provided buffer is {@code null}.
744       *
745       * @throws  IndexOutOfBoundsException  If the specified position is negative
746       *                                     or greater than the current length.
747       */
748      public ByteStringBuffer insert(final int pos, final ByteStringBuffer buffer)
749             throws NullPointerException, IndexOutOfBoundsException
750      {
751        if (buffer == null)
752        {
753          final NullPointerException e =
754               new NullPointerException(ERR_BS_BUFFER_BUFFER_NULL.get());
755          debugCodingError(e);
756          throw e;
757        }
758    
759        return insert(pos, buffer.array, 0, buffer.endPos);
760      }
761    
762    
763    
764      /**
765       * Inserts the provided character into this buffer at the provided position.
766       *
767       * @param  pos  The position at which the character is to be inserted.
768       * @param  c    The character to be inserted into this buffer.
769       *
770       * @return  A reference to this buffer.
771       *
772       * @throws  IndexOutOfBoundsException  If the specified position is negative
773       *                                     or greater than the current length.
774       */
775      public ByteStringBuffer insert(final int pos, final char c)
776             throws IndexOutOfBoundsException
777      {
778        if ((pos < 0) || (pos > endPos))
779        {
780          final String message;
781          if (pos < 0)
782          {
783            message = ERR_BS_BUFFER_POS_NEGATIVE.get(pos);
784          }
785          else
786          {
787            message = ERR_BS_BUFFER_POS_TOO_LARGE.get(pos, endPos);
788          }
789    
790          final IndexOutOfBoundsException e =
791               new IndexOutOfBoundsException(message);
792          debugCodingError(e);
793          throw e;
794        }
795        else if (pos == endPos)
796        {
797          return append(c);
798        }
799    
800        final byte b = (byte) (c & 0x7F);
801        if (b == c)
802        {
803          ensureCapacity(endPos + 1);
804          System.arraycopy(array, pos, array, pos+1, (endPos-pos));
805          array[pos] = b;
806          endPos++;
807        }
808        else
809        {
810          insert(pos, String.valueOf(c));
811        }
812    
813        return this;
814      }
815    
816    
817    
818      /**
819       * Inserts the contents of the provided character array into this buffer at
820       * the specified position.
821       *
822       * @param  pos  The position at which the data is to be inserted.
823       * @param  c    The array whose contents should be inserted into this buffer.
824       *
825       * @return  A reference to this buffer.
826       *
827       * @throws  NullPointerException  If the provided array is {@code null}.
828       *
829       * @throws  IndexOutOfBoundsException  If the specified position is negative
830       *                                     or greater than the current length.
831       */
832      public ByteStringBuffer insert(final int pos, final char[] c)
833             throws NullPointerException, IndexOutOfBoundsException
834      {
835        if (c == null)
836        {
837          final NullPointerException e =
838               new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get());
839          debugCodingError(e);
840          throw e;
841        }
842    
843        return insert(pos, new String(c, 0, c.length));
844      }
845    
846    
847    
848      /**
849       * Inserts the specified portion of the provided character array to this
850       * buffer at the specified position.
851       *
852       * @param  pos  The position at which the data is to be inserted.
853       * @param  c    The array whose contents should be inserted into this buffer.
854       * @param  off  The offset within the array at which to begin copying data.
855       * @param  len  The number of characters to copy.
856       *
857       * @return  A reference to this buffer.
858       *
859       * @throws  NullPointerException  If the provided array is {@code null}.
860       *
861       * @throws  IndexOutOfBoundsException  If the specified position is negative
862       *                                     or greater than the current length, if
863       *                                     the offset or length are negative, if
864       *                                     the offset plus the length is beyond
865       *                                     the end of the provided array.
866       */
867      public ByteStringBuffer insert(final int pos, final char[] c, final int off,
868                                     final int len)
869             throws NullPointerException, IndexOutOfBoundsException
870      {
871        if (c == null)
872        {
873          final NullPointerException e =
874               new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get());
875          debugCodingError(e);
876          throw e;
877        }
878    
879        return insert(pos, new String(c, off, len));
880      }
881    
882    
883    
884      /**
885       * Inserts the provided character sequence to this buffer at the specified
886       * position.
887       *
888       * @param  pos  The position at which the data is to be inserted.
889       * @param  s    The character sequence to insert into this buffer.
890       *
891       * @return  A reference to this buffer.
892       *
893       * @throws  NullPointerException  If the provided character sequence is
894       *                                {@code null}.
895       *
896       * @throws  IndexOutOfBoundsException  If the specified position is negative
897       *                                     or greater than the current length.
898       */
899      public ByteStringBuffer insert(final int pos, final CharSequence s)
900             throws NullPointerException, IndexOutOfBoundsException
901      {
902        if (s == null)
903        {
904          final NullPointerException e =
905               new NullPointerException(ERR_BS_BUFFER_CHAR_SEQUENCE_NULL.get());
906          debugCodingError(e);
907          throw e;
908        }
909    
910        if ((pos < 0) || (pos > endPos))
911        {
912          final String message;
913          if (pos < 0)
914          {
915            message = ERR_BS_BUFFER_POS_NEGATIVE.get(pos);
916          }
917          else
918          {
919            message = ERR_BS_BUFFER_POS_TOO_LARGE.get(pos, endPos);
920          }
921    
922          final IndexOutOfBoundsException e =
923               new IndexOutOfBoundsException(message);
924          debugCodingError(e);
925          throw e;
926        }
927        else if (pos == endPos)
928        {
929          return append(s);
930        }
931        else
932        {
933          return insert(pos, StaticUtils.getBytes(s.toString()));
934        }
935      }
936    
937    
938    
939      /**
940       * Inserts the provided integer value to this buffer.
941       *
942       * @param  pos  The position at which the value is to be inserted.
943       * @param  i    The integer value to be inserted into this buffer.
944       *
945       * @return  A reference to this buffer.
946       *
947       * @throws  IndexOutOfBoundsException  If the specified position is negative
948       *                                     or greater than the current length.
949       */
950      public ByteStringBuffer insert(final int pos, final int i)
951             throws IndexOutOfBoundsException
952      {
953        final int length = getBytes(i);
954        return insert(pos, TEMP_NUMBER_BUFFER.get(), 0, length);
955      }
956    
957    
958    
959      /**
960       * Inserts the provided long value to this buffer.
961       *
962       * @param  pos  The position at which the value is to be inserted.
963       * @param  l    The long value to be inserted into this buffer.
964       *
965       * @return  A reference to this buffer.
966       *
967       * @throws  IndexOutOfBoundsException  If the specified position is negative
968       *                                     or greater than the current length.
969       */
970      public ByteStringBuffer insert(final int pos, final long l)
971             throws IndexOutOfBoundsException
972      {
973        final int length = getBytes(l);
974        return insert(pos, TEMP_NUMBER_BUFFER.get(), 0, length);
975      }
976    
977    
978    
979      /**
980       * Deletes the specified number of bytes from the beginning of the buffer.
981       *
982       * @param  len  The number of bytes to delete.
983       *
984       * @return  A reference to this buffer.
985       *
986       * @throws  IndexOutOfBoundsException  If the specified length is negative,
987       *                                     or if it is greater than the number of
988       *                                     bytes currently contained in this
989       *                                     buffer.
990       */
991      public ByteStringBuffer delete(final int len)
992             throws IndexOutOfBoundsException
993      {
994        return delete(0, len);
995      }
996    
997    
998    
999      /**
1000       * Deletes the indicated number of bytes from the specified location in the
1001       * buffer.
1002       *
1003       * @param  off  The position in the buffer at which the content to delete
1004       *              begins.
1005       * @param  len  The number of bytes to remove from the buffer.
1006       *
1007       * @return  A reference to this buffer.
1008       *
1009       * @throws  IndexOutOfBoundsException  If the offset or length is negative, or
1010       *                                     if the combination of the offset and
1011       *                                     length is greater than the end of the
1012       *                                     content in the buffer.
1013       */
1014      public ByteStringBuffer delete(final int off, final int len)
1015             throws IndexOutOfBoundsException
1016      {
1017        if (off < 0)
1018        {
1019          throw new IndexOutOfBoundsException(
1020               ERR_BS_BUFFER_OFFSET_NEGATIVE.get(off));
1021        }
1022        else if (len < 0)
1023        {
1024          throw new IndexOutOfBoundsException(
1025               ERR_BS_BUFFER_LENGTH_NEGATIVE.get(len));
1026        }
1027        else if ((off + len) > endPos)
1028        {
1029          throw new IndexOutOfBoundsException(
1030               ERR_BS_BUFFER_OFFSET_PLUS_LENGTH_TOO_LARGE.get(off, len, endPos));
1031        }
1032        else if (len == 0)
1033        {
1034          return this;
1035        }
1036        else if (off == 0)
1037        {
1038          if (len == endPos)
1039          {
1040            endPos = 0;
1041            return this;
1042          }
1043          else
1044          {
1045            final int newEndPos = endPos - len;
1046            System.arraycopy(array, len, array, 0, newEndPos);
1047            endPos = newEndPos;
1048            return this;
1049          }
1050        }
1051        else
1052        {
1053          if ((off + len) == endPos)
1054          {
1055            endPos = off;
1056            return this;
1057          }
1058          else
1059          {
1060            final int bytesToCopy = endPos - (off+len);
1061            System.arraycopy(array, (off+len), array, off, bytesToCopy);
1062            endPos -= len;
1063            return this;
1064          }
1065        }
1066      }
1067    
1068    
1069    
1070      /**
1071       * Sets the contents of this buffer to include only the provided boolean
1072       * value.
1073       *
1074       * @param  b  The boolean value to use as the content for this buffer.
1075       *
1076       * @return  A reference to this buffer.
1077       */
1078      public ByteStringBuffer set(final boolean b)
1079      {
1080        if (b)
1081        {
1082          return set(TRUE_VALUE_BYTES, 0, 4);
1083        }
1084        else
1085        {
1086          return set(FALSE_VALUE_BYTES, 0, 5);
1087        }
1088      }
1089    
1090    
1091    
1092      /**
1093       * Sets the contents of this buffer to include only the provided byte.
1094       *
1095       * @param  b  The byte to use as the content for this buffer.
1096       *
1097       * @return  A reference to this buffer.
1098       */
1099      public ByteStringBuffer set(final byte b)
1100      {
1101        endPos = 0;
1102        return append(b);
1103      }
1104    
1105    
1106    
1107      /**
1108       * Sets the contents of this buffer to the contents of the provided byte
1109       * array.
1110       *
1111       * @param  b  The byte array containing the content to use for this buffer.
1112       *
1113       * @throws  NullPointerException  If the provided array is {@code null}.
1114       *
1115       * @return  A reference to this buffer.
1116       */
1117      public ByteStringBuffer set(final byte[] b)
1118             throws NullPointerException
1119      {
1120        if (b == null)
1121        {
1122          final NullPointerException e =
1123               new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get());
1124          debugCodingError(e);
1125          throw e;
1126        }
1127    
1128        endPos = 0;
1129        return append(b, 0, b.length);
1130      }
1131    
1132    
1133    
1134      /**
1135       * Sets the contents of this buffer to the specified portion of the provided
1136       * byte array.
1137       *
1138       * @param  b    The byte array containing the content to use for this buffer.
1139       * @param  off  The offset within the array at which to begin copying data.
1140       * @param  len  The number of bytes to copy.
1141       *
1142       * @return  A reference to this buffer.
1143       *
1144       * @throws  NullPointerException  If the provided array is {@code null}.
1145       *
1146       * @throws  IndexOutOfBoundsException  If the offset or length are negative,
1147       *                                     if the offset plus the length is beyond
1148       *                                     the end of the provided array.
1149       */
1150      public ByteStringBuffer set(final byte[] b, final int off, final int len)
1151             throws NullPointerException, IndexOutOfBoundsException
1152      {
1153        if (b == null)
1154        {
1155          final NullPointerException e =
1156               new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get());
1157          debugCodingError(e);
1158          throw e;
1159        }
1160    
1161        if ((off < 0) || (len < 0) || (off+len > b.length))
1162        {
1163          final String message;
1164          if (off < 0)
1165          {
1166            message = ERR_BS_BUFFER_OFFSET_NEGATIVE.get(off);
1167          }
1168          else if (len < 0)
1169          {
1170            message = ERR_BS_BUFFER_LENGTH_NEGATIVE.get(len);
1171          }
1172          else
1173          {
1174            message = ERR_BS_BUFFER_OFFSET_PLUS_LENGTH_TOO_LARGE.get(off, len,
1175                                                                     b.length);
1176          }
1177    
1178          final IndexOutOfBoundsException e =
1179               new IndexOutOfBoundsException(message);
1180          debugCodingError(e);
1181          throw e;
1182        }
1183    
1184        endPos = 0;
1185        return append(b, off, len);
1186      }
1187    
1188    
1189    
1190      /**
1191       * Sets the contents of this buffer to the contents of the provided byte
1192       * string.
1193       *
1194       * @param  b  The byte string that should be used as the content for this
1195       *            buffer.
1196       *
1197       * @throws  NullPointerException  If the provided byte string is {@code null}.
1198       *
1199       * @return  A reference to this buffer.
1200       */
1201      public ByteStringBuffer set(final ByteString b)
1202             throws NullPointerException
1203      {
1204        if (b == null)
1205        {
1206          final NullPointerException e =
1207               new NullPointerException(ERR_BS_BUFFER_BYTE_STRING_NULL.get());
1208          debugCodingError(e);
1209          throw e;
1210        }
1211    
1212        endPos = 0;
1213        b.appendValueTo(this);
1214        return this;
1215      }
1216    
1217    
1218    
1219      /**
1220       * Sets the contents of this buffer to the contents of the provided byte
1221       * string buffer.
1222       *
1223       * @param  buffer  The buffer whose contents should be used as the content for
1224       *                 this buffer.
1225       *
1226       * @throws  NullPointerException  If the provided buffer is {@code null}.
1227       *
1228       * @return  A reference to this buffer.
1229       */
1230      public ByteStringBuffer set(final ByteStringBuffer buffer)
1231             throws NullPointerException
1232      {
1233        if (buffer == null)
1234        {
1235          final NullPointerException e =
1236               new NullPointerException(ERR_BS_BUFFER_BUFFER_NULL.get());
1237          debugCodingError(e);
1238          throw e;
1239        }
1240    
1241        endPos = 0;
1242        return append(buffer.array, 0, buffer.endPos);
1243      }
1244    
1245    
1246    
1247      /**
1248       * Sets the contents of this buffer to include only the provided character.
1249       *
1250       * @param  c  The character use as the content for this buffer.
1251       *
1252       * @return  A reference to this buffer.
1253       */
1254      public ByteStringBuffer set(final char c)
1255      {
1256        endPos = 0;
1257        return append(c);
1258      }
1259    
1260    
1261    
1262      /**
1263       * Sets the contents of this buffer to the contents of the provided character
1264       * array.
1265       *
1266       * @param  c  The character array containing the content to use for this
1267       *            buffer.
1268       *
1269       * @throws  NullPointerException  If the provided array is {@code null}.
1270       *
1271       * @return  A reference to this buffer.
1272       */
1273      public ByteStringBuffer set(final char[] c)
1274             throws NullPointerException
1275      {
1276        if (c == null)
1277        {
1278          final NullPointerException e =
1279               new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get());
1280          debugCodingError(e);
1281          throw e;
1282        }
1283    
1284        endPos = 0;
1285        return append(c, 0, c.length);
1286      }
1287    
1288    
1289    
1290      /**
1291       * Sets the contents of this buffer to the specified portion of the provided
1292       * character array.
1293       *
1294       * @param  c    The character array containing the content to use for this
1295       *              buffer.
1296       * @param  off  The offset within the array at which to begin copying data.
1297       * @param  len  The number of characters to copy.
1298       *
1299       * @return  A reference to this buffer.
1300       *
1301       * @throws  NullPointerException  If the provided array is {@code null}.
1302       *
1303       * @throws  IndexOutOfBoundsException  If the offset or length are negative,
1304       *                                     if the offset plus the length is beyond
1305       *                                     the end of the provided array.
1306       */
1307      public ByteStringBuffer set(final char[] c, final int off, final int len)
1308             throws NullPointerException, IndexOutOfBoundsException
1309      {
1310        if (c == null)
1311        {
1312          final NullPointerException e =
1313               new NullPointerException(ERR_BS_BUFFER_ARRAY_NULL.get());
1314          debugCodingError(e);
1315          throw e;
1316        }
1317    
1318        if ((off < 0) || (len < 0) || (off+len > c.length))
1319        {
1320          final String message;
1321          if (off < 0)
1322          {
1323            message = ERR_BS_BUFFER_OFFSET_NEGATIVE.get(off);
1324          }
1325          else if (len < 0)
1326          {
1327            message = ERR_BS_BUFFER_LENGTH_NEGATIVE.get(len);
1328          }
1329          else
1330          {
1331            message = ERR_BS_BUFFER_OFFSET_PLUS_LENGTH_TOO_LARGE.get(off, len,
1332                                                                     c.length);
1333          }
1334    
1335          final IndexOutOfBoundsException e =
1336               new IndexOutOfBoundsException(message);
1337          debugCodingError(e);
1338          throw e;
1339        }
1340    
1341        endPos = 0;
1342        return append(c, off, len);
1343      }
1344    
1345    
1346    
1347      /**
1348       * Sets the contents of this buffer to the specified portion of the provided
1349       * character sequence.
1350       *
1351       * @param  s  The character sequence to use as the content for this buffer.
1352       *
1353       * @throws  NullPointerException  If the provided character sequence is
1354       *                                {@code null}.
1355       *
1356       * @return  A reference to this buffer.
1357       */
1358      public ByteStringBuffer set(final CharSequence s)
1359             throws NullPointerException
1360      {
1361        if (s == null)
1362        {
1363          final NullPointerException e =
1364               new NullPointerException(ERR_BS_BUFFER_CHAR_SEQUENCE_NULL.get());
1365          debugCodingError(e);
1366          throw e;
1367        }
1368    
1369        endPos = 0;
1370        return append(s);
1371      }
1372    
1373    
1374    
1375      /**
1376       * Sets the contents of this buffer to include only the provided integer
1377       * value.
1378       *
1379       * @param  i  The integer value to use as the content for this buffer.
1380       *
1381       * @return  A reference to this buffer.
1382       */
1383      public ByteStringBuffer set(final int i)
1384      {
1385        final int length = getBytes(i);
1386        return set(TEMP_NUMBER_BUFFER.get(), 0, length);
1387      }
1388    
1389    
1390    
1391      /**
1392       * Sets the contents of this buffer to include only the provided long value.
1393       *
1394       * @param  l  The long value to use as the content for this buffer.
1395       *
1396       * @return  A reference to this buffer.
1397       */
1398      public ByteStringBuffer set(final long l)
1399      {
1400        final int length = getBytes(l);
1401        return set(TEMP_NUMBER_BUFFER.get(), 0, length);
1402      }
1403    
1404    
1405    
1406      /**
1407       * Clears the contents of this buffer.
1408       *
1409       * @return  A reference to this buffer.
1410       */
1411      public ByteStringBuffer clear()
1412      {
1413        endPos = 0;
1414        return this;
1415      }
1416    
1417    
1418    
1419      /**
1420       * Clears the contents of this buffer.
1421       *
1422       * @param  zero  Indicates whether to overwrite the content of the backing
1423       *               array with all zeros in order to wipe out any sensitive data
1424       *               it may contain.
1425       *
1426       * @return  A reference to this buffer.
1427       */
1428      public ByteStringBuffer clear(final boolean zero)
1429      {
1430        endPos = 0;
1431    
1432        if (zero)
1433        {
1434          Arrays.fill(array, (byte) 0x00);
1435        }
1436    
1437        return this;
1438      }
1439    
1440    
1441    
1442      /**
1443       * Retrieves the current backing array for this buffer.  The data will begin
1444       * at position 0 and will contain {@code ByteStringBuffer#length} bytes.
1445       *
1446       * @return  The current backing array for this buffer.
1447       */
1448      public byte[] getBackingArray()
1449      {
1450        return array;
1451      }
1452    
1453    
1454    
1455      /**
1456       * Indicates whether this buffer is currently empty.
1457       *
1458       * @return  {@code true} if this buffer is currently empty, or {@code false}
1459       *          if not.
1460       */
1461      public boolean isEmpty()
1462      {
1463        return (endPos == 0);
1464      }
1465    
1466    
1467    
1468      /**
1469       * Retrieves the number of bytes contained in this buffer.
1470       *
1471       * @return  The number of bytes contained in this buffer.
1472       */
1473      public int length()
1474      {
1475        return endPos;
1476      }
1477    
1478    
1479    
1480      /**
1481       * Sets the length of this buffer to the specified value.  If the new length
1482       * is greater than the current length, the value will be padded with zeroes.
1483       *
1484       * @param  length  The new length to use for the buffer.  It must be greater
1485       *                 than or equal to zero.
1486       *
1487       * @throws  IndexOutOfBoundsException  If the provided length is negative.
1488       */
1489      public void setLength(final int length)
1490             throws IndexOutOfBoundsException
1491      {
1492        if (length < 0)
1493        {
1494          final IndexOutOfBoundsException e = new IndexOutOfBoundsException(
1495               ERR_BS_BUFFER_LENGTH_NEGATIVE.get(length));
1496          debugCodingError(e);
1497          throw e;
1498        }
1499    
1500        if (length > endPos)
1501        {
1502          ensureCapacity(length);
1503          Arrays.fill(array, endPos, length, (byte) 0x00);
1504          endPos = length;
1505        }
1506        else
1507        {
1508          endPos = length;
1509        }
1510      }
1511    
1512    
1513    
1514      /**
1515       * Returns the current capacity for this buffer.
1516       *
1517       * @return  The current capacity for this buffer.
1518       */
1519      public int capacity()
1520      {
1521        return capacity;
1522      }
1523    
1524    
1525    
1526      /**
1527       * Ensures that the total capacity of this buffer is at least equal to the
1528       * specified size.
1529       *
1530       * @param  minimumCapacity  The minimum capacity for this buffer.
1531       */
1532      public void ensureCapacity(final int minimumCapacity)
1533      {
1534        if (capacity < minimumCapacity)
1535        {
1536          final int newCapacity = Math.max(minimumCapacity, (2 * capacity) + 2);
1537          final byte[] newArray = new byte[newCapacity];
1538          System.arraycopy(array, 0, newArray, 0, capacity);
1539          array = newArray;
1540          capacity = newCapacity;
1541        }
1542      }
1543    
1544    
1545    
1546      /**
1547       * Sets the capacity equal to the specified value.  If the provided capacity
1548       * is less than the current length, then the length will be reduced to the
1549       * new capacity.
1550       *
1551       * @param  capacity  The new capacity for this buffer.  It must be greater
1552       *                   than or equal to zero.
1553       *
1554       * @throws  IndexOutOfBoundsException  If the provided capacity is negative.
1555       */
1556      public void setCapacity(final int capacity)
1557             throws IndexOutOfBoundsException
1558      {
1559        if (capacity < 0)
1560        {
1561          final IndexOutOfBoundsException e = new IndexOutOfBoundsException(
1562               ERR_BS_BUFFER_CAPACITY_NEGATIVE.get(capacity));
1563          debugCodingError(e);
1564          throw e;
1565        }
1566    
1567        if (this.capacity == capacity)
1568        {
1569          return;
1570        }
1571        else if (this.capacity < capacity)
1572        {
1573          final byte[] newArray = new byte[capacity];
1574          System.arraycopy(array, 0, newArray, 0, this.capacity);
1575          array = newArray;
1576          this.capacity = capacity;
1577        }
1578        else
1579        {
1580          final byte[] newArray = new byte[capacity];
1581          System.arraycopy(array, 0, newArray, 0, capacity);
1582          array = newArray;
1583          endPos = Math.min(endPos, capacity);
1584          this.capacity = capacity;
1585        }
1586      }
1587    
1588    
1589    
1590      /**
1591       * Trims the backing array to the minimal size required for this buffer.
1592       *
1593       * @return  A reference to this buffer.
1594       */
1595      public ByteStringBuffer trimToSize()
1596      {
1597        if (endPos != capacity)
1598        {
1599          final byte[] newArray = new byte[endPos];
1600          System.arraycopy(array, 0, newArray, 0, endPos);
1601          array = newArray;
1602          capacity = endPos;
1603        }
1604    
1605        return this;
1606      }
1607    
1608    
1609    
1610      /**
1611       * Returns a new byte array with the content from this buffer.
1612       *
1613       * @return  A byte array containing the content from this buffer.
1614       */
1615      public byte[] toByteArray()
1616      {
1617        final byte[] newArray = new byte[endPos];
1618        System.arraycopy(array, 0, newArray, 0, endPos);
1619        return newArray;
1620      }
1621    
1622    
1623    
1624      /**
1625       * Returns a new byte string with the content from this buffer.
1626       *
1627       * @return  A byte string with the content from this buffer.
1628       */
1629      public ByteString toByteString()
1630      {
1631        return new ASN1OctetString(toByteArray());
1632      }
1633    
1634    
1635    
1636      /**
1637       * Creates an input stream that may be used to read content from this buffer.
1638       * This buffer should not be altered while the input stream is being used.
1639       *
1640       * @return  An input stream that may be used to read content from this buffer.
1641       */
1642      public InputStream asInputStream()
1643      {
1644        return new ByteArrayInputStream(array, 0, endPos);
1645      }
1646    
1647    
1648    
1649      /**
1650       * Writes the contents of this byte string buffer to the provided output
1651       * stream.
1652       *
1653       * @param  outputStream  The output stream to which the data should be
1654       *                       written.
1655       *
1656       * @throws  IOException  If a problem occurs while writing to the provided
1657       *                       output stream.
1658       */
1659      public void write(final OutputStream outputStream)
1660             throws IOException
1661      {
1662        outputStream.write(array, 0, endPos);
1663      }
1664    
1665    
1666    
1667      /**
1668       * Adds the bytes comprising the string representation of the provided long
1669       * value to the temporary number buffer.
1670       *
1671       * @param  l  The long value to be appended.
1672       *
1673       * @return  The number of bytes in the string representation of the value.
1674       */
1675      private static int getBytes(final long l)
1676      {
1677        // NOTE:  This method is probably not as efficient as it could be, but it is
1678        // more important to avoid the need for memory allocation.
1679        byte[] b = TEMP_NUMBER_BUFFER.get();
1680        if (b == null)
1681        {
1682          b = new byte[20];
1683          TEMP_NUMBER_BUFFER.set(b);
1684        }
1685    
1686        if (l == Long.MIN_VALUE)
1687        {
1688          b[0]  = '-';
1689          b[1]  = '9';
1690          b[2]  = '2';
1691          b[3]  = '2';
1692          b[4]  = '3';
1693          b[5]  = '3';
1694          b[6]  = '7';
1695          b[7]  = '2';
1696          b[8]  = '0';
1697          b[9]  = '3';
1698          b[10] = '6';
1699          b[11] = '8';
1700          b[12] = '5';
1701          b[13] = '4';
1702          b[14] = '7';
1703          b[15] = '7';
1704          b[16] = '5';
1705          b[17] = '8';
1706          b[18] = '0';
1707          b[19] = '8';
1708          return 20;
1709        }
1710        else if (l == 0L)
1711        {
1712          b[0] = '0';
1713          return 1;
1714        }
1715    
1716        int pos = 0;
1717        long v = l;
1718        if (l < 0)
1719        {
1720          b[0] = '-';
1721          pos = 1;
1722          v = Math.abs(l);
1723        }
1724    
1725        long divisor;
1726        if (v <= 9L)
1727        {
1728          divisor = 1L;
1729        }
1730        else if (v <= 99L)
1731        {
1732          divisor = 10L;
1733        }
1734        else if (v <= 999L)
1735        {
1736          divisor = 100L;
1737        }
1738        else if (v <= 9999L)
1739        {
1740          divisor = 1000L;
1741        }
1742        else if (v <= 99999L)
1743        {
1744          divisor = 10000L;
1745        }
1746        else if (v <= 999999L)
1747        {
1748          divisor = 100000L;
1749        }
1750        else if (v <= 9999999L)
1751        {
1752          divisor = 1000000L;
1753        }
1754        else if (v <= 99999999L)
1755        {
1756          divisor = 10000000L;
1757        }
1758        else if (v <= 999999999L)
1759        {
1760          divisor = 100000000L;
1761        }
1762        else if (v <= 9999999999L)
1763        {
1764          divisor = 1000000000L;
1765        }
1766        else if (v <= 99999999999L)
1767        {
1768          divisor = 10000000000L;
1769        }
1770        else if (v <= 999999999999L)
1771        {
1772          divisor = 100000000000L;
1773        }
1774        else if (v <= 9999999999999L)
1775        {
1776          divisor = 1000000000000L;
1777        }
1778        else if (v <= 99999999999999L)
1779        {
1780          divisor = 10000000000000L;
1781        }
1782        else if (v <= 999999999999999L)
1783        {
1784          divisor = 100000000000000L;
1785        }
1786        else if (v <= 9999999999999999L)
1787        {
1788          divisor = 1000000000000000L;
1789        }
1790        else if (v <= 99999999999999999L)
1791        {
1792          divisor = 10000000000000000L;
1793        }
1794        else if (v <= 999999999999999999L)
1795        {
1796          divisor = 100000000000000000L;
1797        }
1798        else
1799        {
1800          divisor = 1000000000000000000L;
1801        }
1802    
1803        while (true)
1804        {
1805          final long digit = v / divisor;
1806          switch ((int) digit)
1807          {
1808            case 0:
1809              b[pos++] = '0';
1810              break;
1811            case 1:
1812              b[pos++] = '1';
1813              break;
1814            case 2:
1815              b[pos++] = '2';
1816              break;
1817            case 3:
1818              b[pos++] = '3';
1819              break;
1820            case 4:
1821              b[pos++] = '4';
1822              break;
1823            case 5:
1824              b[pos++] = '5';
1825              break;
1826            case 6:
1827              b[pos++] = '6';
1828              break;
1829            case 7:
1830              b[pos++] = '7';
1831              break;
1832            case 8:
1833              b[pos++] = '8';
1834              break;
1835            case 9:
1836              b[pos++] = '9';
1837              break;
1838          }
1839    
1840          if (divisor == 1L)
1841          {
1842            break;
1843          }
1844          else
1845          {
1846            v -= (divisor * digit);
1847            if (v == 0)
1848            {
1849              while (divisor > 1L)
1850              {
1851                b[pos++] = '0';
1852                divisor /= 10L;
1853              }
1854    
1855              break;
1856            }
1857    
1858            divisor /= 10L;
1859          }
1860        }
1861    
1862        return pos;
1863      }
1864    
1865    
1866    
1867      /**
1868       * Retrieves a hash code for this byte array.
1869       *
1870       * @return  A hash code for this byte array.
1871       */
1872      @Override()
1873      public int hashCode()
1874      {
1875        int hashCode = 0;
1876    
1877        for (int i=0; i < endPos; i++)
1878        {
1879          hashCode += array[i];
1880        }
1881    
1882        return hashCode;
1883      }
1884    
1885    
1886    
1887      /**
1888       * Indicates whether the provided object is a byte string buffer with contents
1889       * that are identical to that of this buffer.
1890       *
1891       * @param  o  The object for which to make the determination.
1892       *
1893       * @return  {@code true} if the provided object is considered equal to this
1894       *          buffer, or {@code false} if not.
1895       */
1896      @Override()
1897      public boolean equals(final Object o)
1898      {
1899        if (o == null)
1900        {
1901          return false;
1902        }
1903    
1904        if (o == this)
1905        {
1906          return true;
1907        }
1908    
1909        if (! (o instanceof ByteStringBuffer))
1910        {
1911          return false;
1912        }
1913    
1914        final ByteStringBuffer b = (ByteStringBuffer) o;
1915        if (endPos != b.endPos)
1916        {
1917          return false;
1918        }
1919    
1920        for (int i=0; i < endPos; i++)
1921        {
1922          if (array[i] != b.array[i])
1923          {
1924            return false;
1925          }
1926        }
1927    
1928        return true;
1929      }
1930    
1931    
1932    
1933      /**
1934       * Creates a duplicate of this byte string buffer.  It will have identical
1935       * content but with a different backing array.  Changes to this byte string
1936       * buffer will not impact the duplicate, and vice-versa.
1937       *
1938       * @return  A duplicate of this byte string buffer.
1939       */
1940      public ByteStringBuffer duplicate()
1941      {
1942        final ByteStringBuffer newBuffer = new ByteStringBuffer(endPos);
1943        return newBuffer.append(this);
1944      }
1945    
1946    
1947    
1948      /**
1949       * Retrieves a string representation of the contents for this buffer.
1950       *
1951       * @return  A string representation of the contents for this buffer.
1952       */
1953      @Override()
1954      public String toString()
1955      {
1956        return StaticUtils.toUTF8String(array, 0, endPos);
1957      }
1958    }