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        }