package ecologylab.generic;
import java.io.IOException;
import java.io.InputStream;
/**
* A mechanism for reading <code>String</code>s from
* <code>java.io.InputStream</code>s of various formats.
* Used especially in drag and drop, for getting values.
*/
public class StringInputStream
extends InputStream
{
public static final int UTF16_LE = 0;
public static final int UTF16_BE = 1;
public static final int UTF16 = UTF16_LE;
public static final int UTF8 = 2;
/**
* Little-endian is like Intel.
* Big-endian is like Power PC.
*/
int outputFormat = UTF16_LE;
/**
* The string from which bytes are read.
*/
protected CharSequence buffer;
/**
* The index of the next character to read from the input stream buffer.
*
* @see java.io.StringBufferInputStream#buffer
*/
protected int pos;
/**
* The number of valid characters in the input stream buffer.
*
* @see java.io.StringBufferInputStream#buffer
*/
protected int count;
/**
* Creates a string input stream to read data from the specified string.
*
* @param charSequence the underlying input buffer.
*/
public StringInputStream(CharSequence charSequence, int format)
{
this(charSequence);
outputFormat = format;
}
public StringInputStream(CharSequence charSequence)
{
this.buffer = charSequence;
count = charSequence.length();
}
/**
* Reads the next byte of data from this input stream. The value
* byte is returned as an <code>int</code> in the range
* <code>0</code> to <code>255</code>. If no byte is available
* because the end of the stream has been reached, the value
* <code>-1</code> is returned.
* <p>
* The <code>read</code> method of
* <code>StringBufferInputStream</code> cannot block. It returns the
* low eight bits of the next character in this input stream's buffer.
*
* @return the next byte of data, or <code>-1</code> if the end of the
* stream is reached.
*/
@Override
public synchronized int read()
{
// Debug.println("StringInputStream.read(");
return (pos < count) ? (int)buffer.charAt(pos++) : -1;
// return (pos < count) ? ((int)(buffer.charAt(pos++)) & 0xFFFF) : -1;
}
@Override
public synchronized int read(byte buf[], int off, int len)
{
// Debug.println("StringInputStream.read(" + len);
if (buf == null)
{
throw new NullPointerException();
} else if ((off < 0) || (off > buf.length) || (len < 0) ||
((off + len) > buf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
}
if (pos >= count)
{
return -1;
}
if (pos + len > count)
{
len = count - pos;
}
if (len <= 0)
{
return 0;
}
CharSequence s = buffer;
int cnt = len;
while (--cnt >= 0)
{
char thisChar = s.charAt(pos++);
// little endian reverses the byte order
byte b1 = (byte) (thisChar & 0xff);
byte b2 = (byte) (thisChar >> 8);
switch (outputFormat)
{
case UTF8:
buf[off++] = b1;
b2 = 0;
break;
case UTF16_LE:
buf[off++] = b1;
buf[off++] = b2;
break;
case UTF16_BE:
buf[off++] = b2;
buf[off++] = b1;
break;
}
// Debug.println(pos + " " + thisChar + " " + b1 + " " + b2);
}
if (outputFormat != UTF8)
len *= 2;
return len;
}
@Override
public int available() throws IOException
{
// Debug.println("StringBufferInputStream.available()");
return count - pos;
}
}