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