package redone.net;
import org.apache.mina.common.IoSession;
/**
* Immutable packet object.
*
* @author Graham
*/
public final class Packet {
public static enum Size {
Fixed, VariableByte, VariableShort
};
/**
* The associated IO session
*/
private final IoSession session;
/**
* The ID of the packet
*/
private final int pID;
/**
* The length of the payload
*/
private final int pLength;
/**
* The payload
*/
private final byte[] pData;
/**
* The current index into the payload buffer for reading
*/
private int caret = 0;
/**
* Whether this packet is without the standard packet header
*/
private final boolean bare;
private Size size = Size.Fixed;
public Packet(IoSession session, int pID, byte[] pData, boolean bare, Size s) {
this.session = session;
this.pID = pID;
this.pData = pData;
pLength = pData.length;
this.bare = bare;
size = s;
}
/**
* Creates a new packet with the specified parameters.
*
* @param session
* The session to associate with the packet
* @param pID
* The ID of the packet
* @param pData
* The payload of the packet
* @param bare
* Whether this packet is bare, which means that it does not
* include the standard packet header
*/
public Packet(IoSession session, int pID, byte[] pData, boolean bare) {
this(session, pID, pData, bare, Size.Fixed);
}
/**
* Creates a new packet with the specified parameters. The packet is
* considered not to be a bare packet.
*
* @param session
* The session to associate with the packet
* @param pID
* The ID of the packet
* @param pData
* The payload the packet
*/
public Packet(IoSession session, int pID, byte[] pData) {
this(session, pID, pData, false);
}
/**
* Returns the IO session associated with the packet, if any.
*
* @return The IoSession object, or null if none.
*/
public IoSession getSession() {
return session;
}
/**
* Checks if this packet is considered to be a bare packet, which means that
* it does not include the standard packet header (ID and length values).
*
* @return Whether this packet is a bare packet
*/
public boolean isBare() {
return bare;
}
public Size getSize() {
return size;
}
/**
* Returns the packet ID.
*
* @return The packet ID
*/
public int getId() {
return pID;
}
/**
* Returns the length of the payload of this packet.
*
* @return The length of the packet's payload
*/
public int getLength() {
return pLength;
}
/**
* Returns the entire payload data of this packet.
*
* @return The payload byte array
*/
public byte[] getData() {
return pData;
}
/**
* Returns the remaining payload data of this packet.
*
* @return The payload byte array
*/
public byte[] getRemainingData() {
byte[] data = new byte[pLength - caret];
for (int i = 0; i < data.length; i++) {
data[i] = pData[i + caret];
}
caret += data.length;
return data;
}
/**
* Reads the next byte from the payload.
*
* @return A byte
*/
public byte readByte() {
return pData[caret++];
}
/**
* Reads the next short from the payload.
*
* @return A short
*/
public short readShort() {
return (short) ((short) ((pData[caret++] & 0xff) << 8) | (short) (pData[caret++] & 0xff));
}
public int readLEShortA() {
int i = (pData[caret++] - 128 & 0xff) + ((pData[caret++] & 0xff) << 8);
if (i > 32767) {
i -= 0x10000;
}
return i;
}
public int readLEShort() {
int i = (pData[caret++] & 0xff) + ((pData[caret++] & 0xff) << 8);
if (i > 32767) {
i -= 0x10000;
}
return i;
}
/**
* Reads the next int from the payload.
*
* @return An int
*/
public int readInt() {
return (pData[caret++] & 0xff) << 24 | (pData[caret++] & 0xff) << 16
| (pData[caret++] & 0xff) << 8 | pData[caret++] & 0xff;
}
public int readLEInt() {
return pData[caret++] & 0xff | (pData[caret++] & 0xff) << 8
| (pData[caret++] & 0xff) << 16 | (pData[caret++] & 0xff) << 24;
}
/**
* Reads the next long from the payload.
*
* @return A long
*/
public long readLong() {
return (long) (pData[caret++] & 0xff) << 56
| (long) (pData[caret++] & 0xff) << 48
| (long) (pData[caret++] & 0xff) << 40
| (long) (pData[caret++] & 0xff) << 32
| (long) (pData[caret++] & 0xff) << 24
| (long) (pData[caret++] & 0xff) << 16
| (long) (pData[caret++] & 0xff) << 8 | pData[caret++] & 0xff;
}
/**
* Reads the string which is formed by the unread portion of the payload.
*
* @return A String
*/
public String readString() {
return readString(pLength - caret);
}
public String readRS2String() {
int start = caret;
while (pData[caret++] != 0) {
;
}
return new String(pData, start, caret - start - 1);
}
public void readBytes(byte[] buf, int off, int len) {
for (int i = 0; i < len; i++) {
buf[off + i] = pData[caret++];
}
}
/**
* Reads a string of the specified length from the payload.
*
* @param length
* The length of the string to be read
* @return A String
*/
public String readString(int length) {
String rv = new String(pData, caret, length);
caret += length;
return rv;
}
/**
* Skips the specified number of bytes in the payload.
*
* @param x
* The number of bytes to be skipped
*/
public void skip(int x) {
caret += x;
}
public int remaining() {
return pData.length - caret;
}
/**
* Returns this packet in string form.
*
* @return A String representing this packet
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[id=" + pID + ",len=" + pLength + ",data=0x");
for (int x = 0; x < pLength; x++) {
sb.append(byteToHex(pData[x], true));
}
sb.append("]");
return sb.toString();
}
private static String byteToHex(byte b, boolean forceLeadingZero) {
StringBuilder out = new StringBuilder();
int ub = b & 0xff;
if (ub / 16 > 0 || forceLeadingZero) {
out.append(hex[ub / 16]);
}
out.append(hex[ub % 16]);
return out.toString();
}
private static final char[] hex = "0123456789ABCDEF".toCharArray();
public int readShortA() {
caret += 2;
return ((pData[caret - 2] & 0xFF) << 8)
+ (pData[caret - 1] - 128 & 0xFF);
}
public byte readByteC() {
return (byte) -readByte();
}
public byte readByteS() {
return (byte) (128 - readByte());
}
}