package com.aionemu.packetsamurai.parser;
import java.io.DataOutput;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UTFDataFormatException;
import java.nio.ByteOrder;
/**
*
* @author Gilles Duboscq
*
*/
public class OrderedDataOutputStream extends FilterOutputStream implements DataOutput
{
private ByteOrder _order;
private byte writeBuffer[] = new byte[8];
/**
* Default order is Little endian
* @param out
*/
public OrderedDataOutputStream(OutputStream out)
{
super(out);
_order = ByteOrder.LITTLE_ENDIAN;
}
/**
*
* @param out
* @param order
*/
public OrderedDataOutputStream(OutputStream out, ByteOrder order)
{
super(out);
_order = order;
}
public synchronized void write(int b) throws IOException
{
out.write(b);
}
public synchronized void write(byte b[], int off, int len) throws IOException
{
out.write(b, off, len);
}
public void writeBoolean(boolean v) throws IOException
{
out.write(v ? 0x01 : 0x00);
}
public void writeByte(int v) throws IOException
{
out.write(v);
}
public void writeBytes(String s) throws IOException
{
int len = s.length();
for (int i = 0 ; i < len ; i++)
{
out.write((byte)s.charAt(i));
}
}
public void writeChar(int v) throws IOException
{
if(_order == ByteOrder.LITTLE_ENDIAN)
{
out.write((v >>> 0) & 0xFF);
out.write((v >>> 8) & 0xFF);
}
else
{
out.write((v >>> 8) & 0xFF);
out.write((v >>> 0) & 0xFF);
}
}
public void writeChars(String s) throws IOException
{
int len = s.length();
for (int i = 0 ; i < len ; i++)
{
writeChar(s.charAt(i));
}
}
public void writeDouble(double v) throws IOException
{
writeLong(Double.doubleToRawLongBits(v));
}
public void writeFloat(float v) throws IOException
{
writeInt(Float.floatToIntBits(v));
}
public void writeInt(int v) throws IOException
{
if(_order == ByteOrder.LITTLE_ENDIAN)
{
out.write((v >>> 0) & 0xFF);
out.write((v >>> 8) & 0xFF);
out.write((v >>> 16) & 0xFF);
out.write((v >>> 24) & 0xFF);
}
else
{
out.write((v >>> 24) & 0xFF);
out.write((v >>> 16) & 0xFF);
out.write((v >>> 8) & 0xFF);
out.write((v >>> 0) & 0xFF);
}
}
public void writeLong(long v) throws IOException
{
if(_order == ByteOrder.LITTLE_ENDIAN)
{
writeBuffer[0] = (byte)(v >>> 0);
writeBuffer[1] = (byte)(v >>> 8);
writeBuffer[2] = (byte)(v >>> 16);
writeBuffer[3] = (byte)(v >>> 24);
writeBuffer[4] = (byte)(v >>> 32);
writeBuffer[5] = (byte)(v >>> 40);
writeBuffer[6] = (byte)(v >>> 48);
writeBuffer[7] = (byte)(v >>> 56);
}
else
{
writeBuffer[0] = (byte)(v >>> 56);
writeBuffer[1] = (byte)(v >>> 48);
writeBuffer[2] = (byte)(v >>> 40);
writeBuffer[3] = (byte)(v >>> 32);
writeBuffer[4] = (byte)(v >>> 24);
writeBuffer[5] = (byte)(v >>> 16);
writeBuffer[6] = (byte)(v >>> 8);
writeBuffer[7] = (byte)(v >>> 0);
}
out.write(writeBuffer, 0, 8);
}
public void writeShort(int v) throws IOException
{
if(_order == ByteOrder.LITTLE_ENDIAN)
{
out.write((v >>> 0) & 0xFF);
out.write((v >>> 8) & 0xFF);
}
else
{
out.write((v >>> 8) & 0xFF);
out.write((v >>> 0) & 0xFF);
}
}
/**
* not really ordered according to the order, using java's UTF-8 standard
*/
public void writeUTF(String str) throws IOException
{
int strlen = str.length();
int utflen = 0;
int c, count = 0;
/* use charAt instead of copying String to char array */
for (int i = 0; i < strlen; i++)
{
c = str.charAt(i);
if ((c >= 0x0001) && (c <= 0x007F))
{
utflen++;
}
else if (c > 0x07FF)
{
utflen += 3;
}
else
{
utflen += 2;
}
}
if (utflen > 65535)
throw new UTFDataFormatException(
"encoded string too long: " + utflen + " bytes");
byte[] bytearr = null;
bytearr = new byte[utflen+2];
bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
int i=0;
for (i=0; i<strlen; i++)
{
c = str.charAt(i);
if (!((c >= 0x0001) && (c <= 0x007F))) break;
bytearr[count++] = (byte) c;
}
for (;i < strlen; i++)
{
c = str.charAt(i);
if ((c >= 0x0001) && (c <= 0x007F))
{
bytearr[count++] = (byte) c;
}
else if (c > 0x07FF)
{
bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
bytearr[count++] = (byte) (0x80 | ((c >> 6) & 0x3F));
bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
}
else
{
bytearr[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
}
}
out.write(bytearr, 0, utflen+2);
}
}