package com.exxeleron.qjava;
import java.io.UnsupportedEncodingException;
import java.nio.ByteOrder;
import java.util.UUID;
/**
* Convenience class for converting wrapped byte buffer to primitive types.
*/
public final class ByteInputStream {
private byte[] buffer;
private int position;
private String encoding;
private ByteInputStreamReader reader;
private ByteInputStreamReader readerLittleEndian;
private ByteInputStreamReader readerBigEndian;
/**
* Creates new {@link ByteInputStream}.
*
* @param encoding
* encoding for symbols conversion
* @param endianess
* byte order of the input stream
*/
public ByteInputStream(final String encoding, final ByteOrder endianess) {
this.encoding = encoding;
this.readerLittleEndian = new ByteLittleEndianInputStream();
this.readerBigEndian = new ByteBigEndianInputStream();
setOrder(endianess);
}
/**
* Wraps byte buffer and resets reading position.
*
* @param newBuffer
* byte buffer to be wrapped
*/
public void wrap( final byte[] newBuffer ) {
buffer = newBuffer;
position = 0;
}
/**
* Copies part of the wrapped byte buffer into a new array.
*
* @param dest
* destination buffer
* @param start
* start position in the wrapped buffer
* @param length
* number of bytes to be copied
*/
public void get( final byte[] dest, final int start, final int length ) {
System.arraycopy(buffer, position, dest, start, length);
position += length;
}
/**
* Retrieves single byte from the wrapped buffer.
*
* @return the <code>byte</code>
*/
public byte get() {
return buffer[position++];
}
/**
* Retrieves single short value from the wrapped buffer.
*
* @return the <code>short</code>
*/
public short getShort() {
return reader.getShort();
}
/**
* Retrieves single int value from the wrapped buffer.
*
* @return the <code>int</code>
*/
public int getInt() {
return reader.getInt();
}
/**
* Retrieves single long value from the wrapped buffer.
*
* @return the <code>long</code>
*/
public long getLong() {
return reader.getLong();
}
/**
* Retrieves single float value from the wrapped buffer.
*
* @return the <code>float</code>
*/
public float getFloat() {
return Float.intBitsToFloat(getInt());
}
/**
* Retrieves single double value from the wrapped buffer.
*
* @return the <code>double</code>
*/
public Double getDouble() {
return Double.longBitsToDouble(getLong());
}
/**
* Retrieves single symbol (Java {@link String}) from the byte buffer.
*
* @return {@link String}
* @throws UnsupportedEncodingException
* if the encoding is unsupported
*/
public String getSymbol() throws UnsupportedEncodingException {
final int p = position;
for ( ; buffer[position++] != 0; ) {
// empty;
}
return (p == position - 1) ? "" : new String(buffer, p, position - 1 - p, encoding);
}
/**
* Retrieves single {@link UUID} from the byte buffer.
*
* @return {@link UUID}
*/
public UUID getUUID() {
final long l1 = readerBigEndian.getLong();
final long l2 = readerBigEndian.getLong();
return new UUID(l1, l2);
}
/**
* Retrieves byte order for the wrapped buffer.
*
* @return {@link ByteOrder}
*/
public ByteOrder getOrder() {
return reader.getOrder();
}
/**
* Sets the byte order for reading the wrapeed buffer.
*
* @param endianess
* byte order
*/
public void setOrder( final ByteOrder endianess ) {
this.reader = endianess.equals(ByteOrder.LITTLE_ENDIAN) ? readerLittleEndian : readerBigEndian;
}
private interface ByteInputStreamReader {
public abstract short getShort();
public abstract int getInt();
public abstract long getLong();
public abstract ByteOrder getOrder();
}
private class ByteBigEndianInputStream implements ByteInputStreamReader {
public short getShort() {
final int x = buffer[position++], y = buffer[position++];
return (short) (x << 8 | y & 0xff);
}
public int getInt() {
final int x = getShort(), y = getShort();
return x << 16 | y & 0xffff;
}
public long getLong() {
final int x = getInt(), y = getInt();
return (long) x << 32 | y & 0xffffffffL;
}
public ByteOrder getOrder() {
return ByteOrder.BIG_ENDIAN;
}
}
private class ByteLittleEndianInputStream implements ByteInputStreamReader {
public short getShort() {
final int x = buffer[position++], y = buffer[position++];
return (short) (x & 0xff | y << 8);
}
public int getInt() {
final int x = getShort(), y = getShort();
return (x & 0xffff | y << 16);
}
public long getLong() {
final int x = getInt(), y = getInt();
return (x & 0xffffffffL | (long) y << 32);
}
public ByteOrder getOrder() {
return ByteOrder.BIG_ENDIAN;
}
}
}