001 package org.hd.d.pg2k.svrCore;
002
003 import java.util.Arrays;
004
005 import org.hd.d.pg2k.svrCore.TextUtils.CharSequence8Bit;
006
007 /**Lightweight CharSequence that wraps a portion of an underlying byte array.
008 * The underlying bytes cannot be altered via this interface,
009 * but changes to the underlying bytes may be visible through this wrapper
010 * (subject to the JMM, if different threads are involved),
011 * ie this is mutable and thus not thread-safe without external synchronisation.
012 */
013 public final class WrappedByteArrayCharSequence implements CharSequence8Bit
014 {
015 /**Underlying 8-bit text; never null. */
016 private final byte[] text;
017 /**Length of exposed fragment, non-negative. */
018 private final int length;
019 /**Offset into underlying buffer, non-negative. */
020 private final int offset;
021
022 /**Expose portion of byte array from offset of specified length. */
023 public WrappedByteArrayCharSequence(final byte text[], final int offset, final int length)
024 {
025 if(null == text) { throw new IllegalArgumentException(); }
026 this.text = text;
027 if((offset < 0) || (offset >= text.length)) { throw new IllegalArgumentException(); }
028 this.offset = offset;
029 if(length < 0) { throw new IllegalArgumentException(); }
030 if(length + offset > text.length) { throw new IllegalArgumentException(); }
031 this.length = length;
032 }
033
034 @Override public int length() { return(length); }
035
036 @Override public byte byteAt(final int index)
037 {
038 if((index < 0) || (index >= length)) { throw new IllegalArgumentException(); }
039 return(text[index + offset]);
040 }
041
042 @Override public char charAt(final int index)
043 { return((char) (byteAt(index) & 0xff)); }
044
045 @Override public CharSequence subSequence(final int start, final int end)
046 {
047 if((start < 0) || (start >= length)) { throw new IllegalArgumentException(); }
048 if((end < start) || (end > length)) { throw new IllegalArgumentException(); }
049 return(new WrappedByteArrayCharSequence(text, offset+start, end-start));
050 }
051
052 @Override public String toString()
053 {
054 final char[] result = new char[length];
055 for(int i = length; --i >= 0; )
056 { result[i] = (char) (text[i + offset] & 0xff); }
057 return(new String(result));
058 }
059
060 /**Return private copy (8-bit) text with each byte corresponding to one char; never null.
061 * May be far more efficient than converting via a String
062 * if the aim is to write directly to a file for example.
063 */
064 public byte[] toByteArray()
065 { return(Arrays.copyOfRange(text, offset, offset+length)); }
066 }