package de.uniluebeck.itm.tcpip;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
/*
* Modifications by Enrico Gueli:
* - replaced LinkedList to ArrayList
* - used the basic List interface
* - toString() implementation
* - standard comments converted to Javadoc
* - getStorageList() made public (but read-only)
*/
public class Storage {
private List<Byte> storageList;
private int position;
private ListIterator<Byte> listIt;
public Storage()
{
storageList = new ArrayList<Byte>();
init();
}
public Storage(byte[] packet)
{
this(packet, 0, packet.length);
}
public Storage(byte[] packet, int offset, int length) {
if (packet == null)
throw new NullPointerException("packet can't be null");
if (length > packet.length)
throw new IndexOutOfBoundsException("length exceeds packet length");
if (offset + length > packet.length)
throw new IndexOutOfBoundsException("content is outside the array");
storageList = new ArrayList<Byte>();
for (int i=offset; i < length; i++)
{
writeByte(packet[i]);
}
init();
}
public Storage(short[] packet)
{
this(packet, 0, packet.length);
}
public Storage(short[] packet, int offset, int length)
{
if (packet == null)
throw new NullPointerException("packet can't be null");
if (length > packet.length)
throw new IndexOutOfBoundsException("length exceeds packet length");
if (offset + length > packet.length)
throw new IndexOutOfBoundsException("content is outside the array");
storageList = new ArrayList<Byte>();
for (int i=offset; i < length; i++)
{
writeByte(packet[i]);
}
init();
}
public boolean validPos()
{
return (position < storageList.size()
&& position >= 0
&& storageList.size() != 0);
}
public int position()
{
return position;
}
/**
* Write a byte value to the List
* a signed value will be converted to its unsigned equivalent first
* @param value the byte to be written
*/
public void writeByte(short value) throws IllegalArgumentException
{
writeByte((int)value);
}
public void writeByte(int value) throws IllegalArgumentException
{
if (value < -128 || value > 127)
throw new IllegalArgumentException("Error writing byte: byte value may only range from -128 to 127.");
storageList.add(new Byte( (byte)(value) ));
}
/**
* Read a byte value from the List
* @return the read byte as an Integer value (unsigned)
*/
public short readByte() throws IllegalStateException
{
if (!validPos())
throw new IllegalStateException("Error reading byte, invalid list position specified for reading: "+position);
position++;
return (short) listIt.next();
}
public void writeUnsignedByte(short value) throws IllegalArgumentException
{
writeUnsignedByte((int) value);
}
public void writeUnsignedByte(int value) throws IllegalArgumentException
{
if (value < 0 || value > 255)
throw new IllegalArgumentException("Error writing unsigned byte: byte value may only range from 0 to 255.");
// 0 -> 0
// 127 -> 127
// 128 -> -128
// 255 -> -1
if (value > 127) storageList.add(new Byte( (byte)(value-256) ));
else storageList.add(new Byte( (byte)(value) ));
}
public short readUnsignedByte() throws IllegalStateException
{
if (!validPos())
throw new IllegalStateException("Error reading unsigned byte, invalid list position specified for reading: "+position);
// -128 -> 128
// -1 -> 255
// 0 -> 0
// 127 -> 127
position++;
return (short) ((listIt.next()+ 256) % 256);
}
/**
* Write a signed short value to the list
* @param value the short value to be written
*/
public void writeShort(int value) throws IllegalArgumentException
{
ByteArrayOutputStream byteOut = new ByteArrayOutputStream(2);
DataOutputStream dataOut = new DataOutputStream(byteOut);
byte bytes[] = new byte[2];
if (value < -32768 || value > 32768)
throw new IllegalArgumentException("Error writing short: short value may only range from -32768 to 32768.");
try {
dataOut.writeShort(value);
dataOut.close();
} catch (IOException e) {
e.printStackTrace();
}
bytes = byteOut.toByteArray();
for (int i=0; i<2; i++)
writeByte(bytes[i]);
}
/**
* Read a short value from the list
* @return the read short value as an Integer
*/
public int readShort() throws IllegalStateException
{
ByteArrayInputStream byteIn;
DataInputStream dataIn;
byte content[] = new byte[2];
int result = 0;
for (int i=0; i<2; i++)
{
content[i] = (byte) readByte();
}
byteIn = new ByteArrayInputStream(content);
dataIn = new DataInputStream(byteIn);
try {
result = dataIn.readShort();
dataIn.close();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
/**
* Write an signed Integer to the list
* the int value is being split up into 4 bytes in msb first order
* @param value the int value to be written
*/
public void writeInt(int value) throws IllegalArgumentException
{
ByteArrayOutputStream byteOut = new ByteArrayOutputStream(4);
DataOutputStream dataOut = new DataOutputStream(byteOut);
byte bytes[] = new byte[4];
try {
dataOut.writeInt(value);
dataOut.close();
} catch (IOException e) {
e.printStackTrace();
}
bytes = byteOut.toByteArray();
for (int i=0; i<4; i++)
writeByte(bytes[i]);
}
/**
* Read a signed integer value, that was split up into 4 bytes
* @return the read int value
*/
public int readInt() throws IllegalStateException
{
ByteArrayInputStream byteIn;
DataInputStream dataIn;
byte content[] = new byte[4];
int result = 0;
for (int i=0; i<4; i++)
{
content[i] = (byte) readByte();
}
byteIn = new ByteArrayInputStream(content);
dataIn = new DataInputStream(byteIn);
try {
result = dataIn.readInt();
dataIn.close();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
/**
* Write a Float to the list
* the float value is beeing split up into 4 bytes in msb first order
* @param value the float value to be written
*/
public void writeFloat(float value) throws IllegalArgumentException
{
ByteArrayOutputStream byteOut = new ByteArrayOutputStream(4);
DataOutputStream dataOut = new DataOutputStream(byteOut);
byte bytes[] = new byte[4];
try {
dataOut.writeFloat(value);
dataOut.close();
} catch (IOException e) {
e.printStackTrace();
}
bytes = byteOut.toByteArray();
for (int i=0; i<4; i++)
writeByte(bytes[i]);
}
/**
* Read a Float value, that was split up into 4 bytes
* @return the read float value
*/
public float readFloat() throws IllegalStateException
{
ByteArrayInputStream byteIn;
DataInputStream dataIn;
byte content[] = new byte[4];
float result = 0;
for (int i=0; i<4; i++)
{
content[i] = (byte) readByte();
}
byteIn = new ByteArrayInputStream(content);
dataIn = new DataInputStream(byteIn);
try {
result = dataIn.readFloat();
dataIn.close();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
/**
* Write a Double to the list
* the value is beeing split up into 8 bytes in msb first order
* @param value the double value to be written
*/
public void writeDouble(double value) throws IllegalArgumentException
{
ByteArrayOutputStream byteOut = new ByteArrayOutputStream(8);
DataOutputStream dataOut = new DataOutputStream(byteOut);
byte bytes[] = new byte[8];
try {
dataOut.writeDouble(value);
dataOut.close();
} catch (IOException e) {
e.printStackTrace();
}
bytes = byteOut.toByteArray();
for (int i=0; i<8; i++)
writeByte(bytes[i]);
}
/**
* Read a Double value, that was split up into 8 bytes
* @return the read double value
*/
public double readDouble() throws IllegalStateException
{
ByteArrayInputStream byteIn;
DataInputStream dataIn;
byte content[] = new byte[8];
double result = 0;
for (int i=0; i<8; i++)
{
content[i] = (byte) readByte();
}
byteIn = new ByteArrayInputStream(content);
dataIn = new DataInputStream(byteIn);
try {
result = dataIn.readDouble();
dataIn.close();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
/**
* Write a string to the list by encoding the characters in UTF-8
* @param value the String to be written
*/
public void writeStringUTF8(String value) throws IllegalArgumentException
{
writeString(value,"UTF-8");
}
/**
* Write a string to the list by encoding the characters in ASCII
* @param value the String to be written
*/
public void writeStringASCII(String value) throws IllegalArgumentException
{
writeString(value,"US-ASCII");
}
/**
* Write a string to the list by encoding the characters in ISO-LATIN1
* @param value the String to be written
*/
public void writeStringISOLATIN1(String value) throws IllegalArgumentException
{
writeString(value,"ISO-8859-1");
}
/**
* Write a string to the list by encoding the characters in UTF-16 Big Endian
* @param value the String to be written
*/
public void writeStringUTF16BE(String value) throws IllegalArgumentException
{
writeString(value,"UTF-16BE");
}
/**
* Write a string to the list by encoding the characters in UTF-16 Little Endian
* @param value the String to be written
*/
public void writeStringUTF16LE(String value) throws IllegalArgumentException
{
writeString(value,"UTF-16LE");
}
private void writeString(String value, String charset) throws IllegalArgumentException
{
byte bytes[];
try {
bytes = value.getBytes(charset);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return;
}
writeInt(value.length());
for (int i=0; i<bytes.length; i++)
writeByte(bytes[i]);
}
/**
* Read a String from the list, that was encoded using UTF-8
* @return the read String
*/
public String readStringUTF8() throws IllegalArgumentException
{
return readString("UTF-8");
}
/**
* Read a String from the list, that was encoded using ASCII
* @return the read String
*/
public String readStringASCII() throws IllegalArgumentException
{
return readString("US-ASCII");
}
/**
* Read a String from the list, that was encoded using ISO-LATIN1
* @return the read String
*/
public String readStringISOLATIN1() throws IllegalArgumentException
{
return readString("ISO-8859-1");
}
/**
* Read a String from the list, that was encoded using UTF-16 Big Endian
* @return the read String
*/
public String readStringUTF16BE() throws IllegalArgumentException
{
return readString("UTF-16BE");
}
/**
* Read a String from the list, that was encoded using UTF-16 Little Endian
* @return the read String
*/
public String readStringUTF16LE() throws IllegalArgumentException
{
return readString("UTF-16LE");
}
private String readString(String charset) throws IllegalStateException
{
byte content[];
String result = new String("");
int length;
length = readInt();
content = new byte[length];
for (int i=0; i<length; i++)
{
content[i] = (byte) readByte();
}
try {
result = new String(content, charset);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
public void reset()
{
storageList.clear();
init();
}
/**
* Retrieve the Size of the internal storage list
* @return size of the storage list
*/
public int size()
{
return storageList.size();
}
/**
* Retrieve the internal list that is used to store the data
* @return the internal storage list
*/
public List<Byte> getStorageList()
{
return Collections.unmodifiableList(storageList);
}
private void init()
{
position = 0;
listIt = storageList.listIterator();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (int i=0; i<storageList.size(); i++) {
if (i == position)
sb.append("[");
else
sb.append(" ");
sb.append(String.format("%02X", storageList.get(i)));
}
return sb.toString();
}
}