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