001/*
002 * Copyright 2008-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2008-2014 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 */
021package com.unboundid.util;
022
023
024
025import java.io.ByteArrayInputStream;
026import java.io.InputStream;
027import java.io.IOException;
028import java.io.OutputStream;
029import java.io.Serializable;
030import java.util.Arrays;
031
032import com.unboundid.asn1.ASN1OctetString;
033
034import static com.unboundid.util.Debug.*;
035import 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)
045public 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}