001 /*
002 * Copyright 2008-2013 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-2013 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 }